diff --git a/build.sbt b/build.sbt index cbcc40979..3c7ce397f 100644 --- a/build.sbt +++ b/build.sbt @@ -150,6 +150,7 @@ lazy val macros = project .settings(name := "caliban-macros") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( libraryDependencies ++= { if (scalaVersion.value == scala3) { @@ -170,6 +171,7 @@ lazy val core = project .settings(name := "caliban") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= @@ -204,6 +206,7 @@ lazy val tools = project .settings(name := "caliban-tools") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( buildInfoKeys := Seq[BuildInfoKey]( "scalaPartialVersion" -> CrossVersion.partialVersion(scalaVersion.value), @@ -231,6 +234,7 @@ lazy val tracing = project .settings(name := "caliban-tracing") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( buildInfoPackage := "caliban.tracing", buildInfoObject := "BuildInfo" @@ -251,6 +255,7 @@ lazy val codegenSbt = project .settings(name := "caliban-codegen-sbt") .settings(commonSettings) .enablePlugins(BuildInfoPlugin) + .disablePlugins(AssemblyPlugin) .settings( skip := (scalaVersion.value != scala212), ideSkipProject := (scalaVersion.value != scala212), @@ -290,6 +295,7 @@ lazy val catsInterop = project .settings(name := "caliban-cats") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= { @@ -310,6 +316,7 @@ lazy val monixInterop = project .settings(name := "caliban-monix") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( libraryDependencies ++= Seq( "dev.zio" %% "zio-interop-reactivestreams" % zioInteropReactiveVersion, @@ -324,6 +331,7 @@ lazy val tapirInterop = project .settings(name := "caliban-tapir") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= { @@ -347,6 +355,7 @@ lazy val http4s = project .settings(name := "caliban-http4s") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= { @@ -374,6 +383,7 @@ lazy val zioHttp = project .settings(name := "caliban-zio-http") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), @@ -391,6 +401,7 @@ lazy val quickAdapter = project .settings(name := "caliban-quick") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= Seq( @@ -407,6 +418,7 @@ lazy val akkaHttp = project .settings(name := "caliban-akka-http") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( skip := (scalaVersion.value == scala3), ideSkipProject := (scalaVersion.value == scala3), @@ -427,6 +439,7 @@ lazy val pekkoHttp = project .settings(name := "caliban-pekko-http") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= { @@ -445,6 +458,7 @@ lazy val play = project .settings(name := "caliban-play") .settings(commonSettings) .settings(enableMimaSettingsJVM) + .disablePlugins(AssemblyPlugin) .settings( skip := (scalaVersion.value == scala212), ideSkipProject := (scalaVersion.value == scala212), @@ -471,6 +485,7 @@ lazy val client = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("client")) .settings(name := "caliban-client") .settings(commonSettings) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= Seq( @@ -515,6 +530,7 @@ lazy val clientLaminext = crossProject(JSPlatform) .settings(commonSettings) .settings(enableMimaSettingsJS) .dependsOn(clientJS) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), Test / scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) }, @@ -535,6 +551,7 @@ lazy val clientLaminext = crossProject(JSPlatform) lazy val examples = project .in(file("examples")) .settings(commonSettings) + .disablePlugins(AssemblyPlugin) .settings( publish / skip := true, run / fork := true, @@ -613,6 +630,7 @@ lazy val reporting = project .settings(commonSettings) .settings(enableMimaSettingsJVM) .dependsOn(clientJVM, core) + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= Seq( @@ -626,6 +644,7 @@ lazy val reporting = project lazy val benchmarks = project .in(file("benchmarks")) .settings(commonSettings) + .disablePlugins(AssemblyPlugin) .settings( skip := (scalaVersion.value == scala212), ideSkipProject := (scalaVersion.value == scala212), @@ -653,6 +672,7 @@ lazy val federation = project .settings(commonSettings) .settings(enableMimaSettingsJVM) .dependsOn(core % "compile->compile;test->test") + .disablePlugins(AssemblyPlugin) .settings( testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")), libraryDependencies ++= Seq( @@ -672,6 +692,7 @@ lazy val docs = project .in(file("mdoc")) .enablePlugins(MdocPlugin) .settings(commonSettings) + .disablePlugins(AssemblyPlugin) .settings( skip := (scalaVersion.value == scala3), ideSkipProject := (scalaVersion.value == scala3), diff --git a/docs/docs/optimization.html b/docs/docs/optimization.html index 1df8563b2..df1d5ad91 100644 --- a/docs/docs/optimization.html +++ b/docs/docs/optimization.html @@ -37,9 +37,7 @@ (opens new window)

# Query optimization

A GraphQL query may request multiple fields that are using the same resolver. It's not a problem if the resolver is a simple value, but it can be less than optimal when the resolver runs an effect (such as reading from a database).

We might want to:

This is possible in Caliban using the ZQuery (opens new window) data type.

Additionally, one may want to perform optimizations based on the fields selected by the client. -This optimization can be achieved by field metadata from Caliban that can be referenced in your query classes.

# Introducing ZQuery

A ZQuery[R, E, A] is a purely functional description of an effectual query that may contain requests to one or more data sources. Similarly to ZIO[R, E, A], it requires an environment R, may fail with an E or succeed with an A. All requests that do not need to be performed sequentially will automatically be batched, allowing for aggressive data source specific optimizations. Requests will also automatically be deduplicated and cached.

This - allows for writing queries in a high level, compositional style, with confidence that they will automatically be - optimized. For example, consider the following query from a user services.

val getAllUserIds: ZQuery[Any, Nothing, List[Int]] = ???
+This optimization can be achieved by field metadata from Caliban that can be referenced in your query classes.

# Introducing ZQuery

A ZQuery[R, E, A] is a purely functional description of an effectual query that may contain requests to one or more data sources. Similarly to ZIO[R, E, A], it requires an environment R, may fail with an E or succeed with an A. All requests that do not need to be performed sequentially will automatically be batched, allowing for aggressive data source specific optimizations. Requests will also automatically be deduplicated and cached.

This allows for writing queries in a high level, compositional style, with confidence that they will automatically be optimized. For example, consider the following query from a user service.

val getAllUserIds: ZQuery[Any, Nothing, List[Int]] = ???
 def getUserNameById(id: Int): ZQuery[Any, Nothing, String] = ???
 
 for {
@@ -73,7 +71,7 @@
   ZQuery.fromRequest(GetUserName(id))(UserDataSource)
 

To run a ZQuery, simply use ZQuery#run which will return a ZIO[R, E, A].

# ZQuery constructors and operators

There are several ways to create a ZQuery. We've seen ZQuery.fromRequest, but you can also:

  • create from a pure value with ZQuery.succeed
  • create from an effect value with ZQuery.fromZIO
  • create from multiple queries with ZQuery.collectAllPar and ZQuery.foreachPar and their sequential equivalents ZQuery.collectAll and ZQuery.foreach

If you have a ZQuery object, you can use:

  • map and mapError to modify the returned result or error
  • flatMap or zip to combine it with other ZQuery objects
  • provide and provideSome to eliminate some of the R requirements

There are several ways to run a ZQuery:

  • runCache runs the query using a given pre-populated cache. This can be useful for deterministically "replaying" a query without executing any new requests.
  • runLog runs the query and returns its result along with the cache containing a complete log of all requests executed and their results. This can be useful for logging or analysis of query execution.
  • run runs the query and returns its result.

# Using ZQuery with Caliban

To use ZQuery with Caliban, you can simply include fields of type ZQuery in your API definition.

case class Queries(
   users: ZQuery[Any, Nothing, List[User]],
-  user: models.UserArgs => ZQuery[Any, Nothing, User])
+  user: UserArgs => ZQuery[Any, Nothing, User])
 

During the query execution, Caliban will merge all the requested fields that return a ZQuery into a single ZQuery and run it, so that all the possible optimizations are applied.

The examples (opens new window) project provides 2 versions of the problem described in this article about GraphQL query optimization (opens new window):

TIP

ZQuery has a lot of operators that are similar to ZIO, such as .optional, etc. Note that just like ZIO, a field returning a ZQuery will be executed only when it is requested by the client.

TIP

When all your effects are wrapped with ZQuery.fromRequest, it is recommended to use queryExecution = QueryExecution.Batched instead of the default QueryExecution.Parallel. Doing so will provide better performance as it will avoid forking unnecessary fibers. diff --git a/vuepress/docs/docs/optimization.md b/vuepress/docs/docs/optimization.md index e404af8bd..73dae015f 100644 --- a/vuepress/docs/docs/optimization.md +++ b/vuepress/docs/docs/optimization.md @@ -116,7 +116,7 @@ To use `ZQuery` with Caliban, you can simply include fields of type `ZQuery` in ```scala case class Queries( users: ZQuery[Any, Nothing, List[User]], - user: models.UserArgs => ZQuery[Any, Nothing, User]) + user: UserArgs => ZQuery[Any, Nothing, User]) ``` During the query execution, Caliban will merge all the requested fields that return a `ZQuery` into a single `ZQuery` and run it, so that all the possible optimizations are applied.