### JDBC Configuration Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-jdbc.md An example of how to configure a JDBC data source in an application.conf file. This includes the data source class name and connection details. ```properties # application.conf myDb.dataSourceClassName = org.postgresql.ds.PGSimpleDataSource myDb.dataSource.databaseName = mydb myDb.dataSource.url = jdbc:postgresql://localhost:5432/mydb myDb.dataSource.user = dbuser myDb.dataSource.password = dbpass ``` -------------------------------- ### CassandraAsyncContext Usage Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Demonstrates setting up and using CassandraAsyncContext for asynchronous Cassandra queries. Includes session setup, context instantiation, query definition, future execution, and session closure within a callback. ```scala import com.datastax.oss.driver.api.core.CqlSession import io.getquill._ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future case class User(id: String, name: String, email: String) val session = CqlSession.builder() .addContactPoint(new InetSocketAddress("localhost", 9042)) .withLocalDatacenter("datacenter1") .build() val ctx = new CassandraAsyncContext(SnakeCase, session) import ctx._ inline def users = quote { query[User].filter(_.id == lift("user123")) } val future: Future[List[User]] = ctx.run(users) future.foreach { users => println(users) session.close() } ``` -------------------------------- ### CqlSession Builder Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Shows how to build a CqlSession with custom configuration, including contact points, local datacenter, and authentication credentials. ```scala val session = CqlSession.builder() .addContactPoint(new InetSocketAddress("localhost", 9042)) .withLocalDatacenter("datacenter1") .withAuthCredentials("username", "password") .build() ``` -------------------------------- ### Setup Databases for Build Source: https://github.com/zio/zio-protoquill/blob/master/build/m1/README.MD Run this command to set up the necessary databases for the build and test process. Ensure you use the `docker-compose-m1.yml` file. ```bash docker compose -f docker-compose-m1.yml --rm setup ``` -------------------------------- ### CassandraZioContext Usage Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Demonstrates how to set up a CqlSession using ZIO's acquireRelease, instantiate CassandraZioContext, define a query, and execute it. ```scala import com.datastax.oss.driver.api.core.CqlSession import io.getquill._ import zio._ case class User(id: String, name: String, email: String) val createSession = ZIO.acquireRelease( ZIO.attempt( CqlSession.builder() .addContactPoint(new InetSocketAddress("localhost", 9042)) .withLocalDatacenter("datacenter1") .build() ) )(session => ZIO.attempt(session.close()).ignoreLogged) val program = for { session <- createSession ctx = new CassandraZioContext(SnakeCase, session) import ctx._ inline def users = quote { query[User].filter(_.id == lift("user123")) } result <- ctx.run(users) _ <- ZIO.debug(result) } yield () object Main extends ZIOAppDefault { def run = program } ``` -------------------------------- ### Dependent Context Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/advanced-features.md Demonstrates how to use dependent contexts in ProtoQuill, allowing for flexible context configurations. This example shows a `PostgresContextHolder`. ```scala abstract class DependentContext { abstract type Dialect <: io.getquill.idiom.Idiom val ctx: io.getquill.context.Context[Dialect, _] } case class PostgresContextHolder(val ctx: PostgresJdbcContext[SnakeCase]) val ctxHolder = PostgresContextHolder(new PostgresJdbcContext(SnakeCase, "pg")) import ctxHolder.ctx._ inline def query = quote { query[Person] } val result = ctxHolder.ctx.run(query) ``` -------------------------------- ### ZIO Context Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Demonstrates using ProtoQuill with ZIO for asynchronous database operations. Requires ZIO and a ZIO-compatible data source layer. ```scala import io.getquill.zio._ import zio._ val dataSourceLayer = ZLayer.succeed(myDataSource) val ctx = new PostgresJdbcZioContext(SnakeCase, dataSourceLayer) import ctx._ val program = for { people <- ctx.run(quote { query[Person] }) count <- ctx.run(quote { query[Person].map(_ => 1).sum }) _ <- ZIO.logInfo(s"Found $count people") } yield people Runtime.default.unsafeRun(program.provideLayer(dataSourceLayer)) ``` -------------------------------- ### Insert Expansion Example Source: https://github.com/zio/zio-protoquill/wiki/Design-Info:-Batch-Query-Execution Shows how an insert statement is expanded, assuming a Person case class with name and age. ```scala // Assuming: Person(name: String, age: Int) Insert(Ident(person /*quat: CC(name->V,age->V)*/)) -> Insert( entity: EntityQuery("Person") Assignment(Ident("_$V"), Property(Ident("_$V"),"name"), Property(Ident("p"), "name")) Assignment(Ident("_$V"), Property(Ident("_$V"),"age"), Property(Ident("p"), "age")) ) ``` -------------------------------- ### GraphQL Query Example Source: https://github.com/zio/zio-protoquill/blob/master/README.md An example GraphQL query used with CalibanExample.scala to demonstrate query planning and optimization. ```graphql query{ personAddressPlan(first: "One") { plan pa { id street first last # Exclude the street column } } } ``` -------------------------------- ### UDT Metadata Definition Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Example demonstrating how to define UDT metadata for an Address case class and use it with a Person case class in a Cassandra context. ```scala case class Address(street: String, city: String, zipCode: String) inline given UdtMeta[Address] = udtMeta( "address_type", _.street -> "street", _.city -> "city", _.zipCode -> "zip_code" ) case class Person(id: String, name: String, address: Address) val ctx = new CassandraSyncContext(Literal, session) import ctx._ inline def query = quote { query[Person].filter(_.address.city == lift("NYC")) } ``` -------------------------------- ### PostgresJdbcContext Construction Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-jdbc.md Example of constructing a PostgresJdbcContext with SnakeCase naming strategy and a loaded configuration. Ensure the configuration file is accessible. ```scala val config = JdbcContextConfig(com.typesafe.config.ConfigFactory.load("application.conf")) val ctx = new PostgresJdbcContext(SnakeCase, config) ``` -------------------------------- ### PostgresJdbcContext Usage Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-jdbc.md Demonstrates how to initialize and use the PostgresJdbcContext for querying, inserting data, and managing transactions. Includes defining a case class and quoting queries. ```scala import io.getquill._ case class Person(id: Int, firstName: String, lastName: String, age: Int) val ctx = new PostgresJdbcContext(SnakeCase, "ctx") import ctx._ // Query inline def adults = quote { query[Person].filter(_.age >= 18) } val people = ctx.run(adults) // Insert inline def insertPerson = quote { query[Person].insertValue(lift(Person(0, "John", "Doe", 30))) } val id = ctx.run(insertPerson) // Transaction ctx.transaction { ctx.run(insertPerson) ctx.run(insertPerson) } ``` -------------------------------- ### Batch Operations Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Demonstrates how to perform batch inserts or updates in Cassandra using ProtoQuill by lifting a list of entities and applying an insert action for each. ```scala val people = List( Person("1", "Alice"), Person("2", "Bob") ) inline def batch = quote { liftQuery(people).foreach(p => query[Person].insertValue(p)) } val result = ctx.run(batch, 25) // 25 statements per batch ``` -------------------------------- ### Quill Caliban Integration Setup Source: https://github.com/zio/zio-protoquill/blob/master/README.md Demonstrates setting up a Quill query with Caliban integration for filtering and column selection. Imports are required for Quill and Caliban integration. ```scala // Import Quill import io.getquill._ // Import the Caliban integration import io.getquill.CalibanIntegration._ // Given some simple schema case class PersonT(id: Int, first: String, last: String, age: Int) case class AddressT(ownerId: Int, street: String) case class PersonAddress(id: Int, first: String, last: String, age: Int, street: Option[String]) // Create a query and add .filterColumns and .filterByKeys to the end inline def peopleAndAddresses(inline columns: List[String], inline filters: Map[String, String]) = quote { // Given a query... query[Person].leftJoin(query[Address]).on((p, a) => p.id == a.ownerId) .map((p, a) => PersonAddress(p.id, p.first, p.last, p.age, a.map(_.street))) // Add these to the end .filterColumns(columns) .filterByKeys(filters) } ``` -------------------------------- ### Compile and Test (excluding codegen) Source: https://github.com/zio/zio-protoquill/blob/master/build/m1/README.MD Execute this command to start the build and run tests, skipping the codegen tests which can sometimes cause phantom errors. Uses the `docker-compose-m1.yml` file. ```bash docker compose -f docker-compose-m1.yml run sbt sbt -Dmodules=db test ``` -------------------------------- ### CassandraSyncContext Usage Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Demonstrates how to set up and use CassandraSyncContext to query user data. Includes session creation, context instantiation, query definition, execution, and session closure. ```scala import com.datastax.oss.driver.api.core.CqlSession import io.getquill._ case class User(id: String, name: String, email: String) val session = CqlSession.builder() .addContactPoint(new InetSocketAddress("localhost", 9042)) .withLocalDatacenter("datacenter1") .build() val ctx = new CassandraSyncContext(SnakeCase, session) { val idiom = CassandraDialect } import ctx._ inline def users = quote { query[User].filter(_.id == lift("user123")) } val result = ctx.run(users) ctx.close() ``` -------------------------------- ### Full ZIO Application with PostgresJdbcZioContext Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-zio.md A complete ZIO application demonstrating the setup and usage of PostgresJdbcZioContext for database operations, including connection pooling and query execution. ```scala import io.getquill._ import zio._ import javax.sql.DataSource case class Person(id: Int, firstName: String, lastName: String, age: Int) object QuillApp extends ZIOAppDefault { val dataSourceLayer = ZLayer.scoped { ZIO.acquireRelease( ZIO.attempt { val ds = new org.postgresql.ds.PGSimpleDataSource() ds.setUrl("jdbc:postgresql://localhost:5432/mydb") ds.setUser("user") ds.setPassword("pass") ds } )(ds => ZIO.attempt(ds.unwrap[java.io.Closeable].close()).ignoreLogged) } val ctx = new PostgresJdbcZioContext(SnakeCase, dataSourceLayer) import ctx._ inline def adults = quote { query[Person].filter(_.age >= 18) } inline def insertPerson = quote { query[Person].insertValue( lift(Person(0, "John", "Doe", 30)) ) } val program = for { people <- ctx.run(adults) _ <- ZIO.logInfo(s"Found ${people.length} adults") rowsInserted <- ctx.run(insertPerson) _ <- ZIO.logInfo(s"Inserted $rowsInserted rows") } yield () override def run = program.provideLayer(dataSourceLayer) } ``` -------------------------------- ### Get SQL Without Execution with MirrorContext Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/mirror-context.md Demonstrates how to use MirrorContext to get the generated SQL for a query without executing it. Imports are required. ```scala val ctx = new MirrorContext(PostgresDialect, SnakeCase) import ctx._ case class Person(firstName: String, lastName: String, age: Int) inline def adults = quote { query[Person].filter(_.age >= 18) } val result = ctx.run(adults) println(result.sql) // Output: // SELECT p.first_name, p.last_name, p.age FROM person p WHERE p.age >= ? ``` -------------------------------- ### Quill Object Usage Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-zio.md Demonstrates how to use the Quill object to create a database context layer, specifying the database type and connection pool. ```scala import io.getquill.zio.Quill val contextLayer = Quill.Postgres( SnakeCase, ZLayer.succeed(myDataSource) ) ``` -------------------------------- ### Closing Cassandra Sessions Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Provides examples for closing Cassandra sessions in both synchronous and asynchronous (ZIO) contexts. ```scala // Synchronous context ctx.close() // Async/ZIO context should close session in a Finally block session.close() ``` -------------------------------- ### Getting Last Executed Query AST (ZIO) Source: https://github.com/zio/zio-protoquill/blob/master/README.md Demonstrates how to get the syntax tree (AST) of the last executed query in a ZIO context using `getLastExecutionInfo()`. Requires the context to extend `AstSplicing`. ```scala val people = for { // First create a quill-zio context. Be sure that it extends AstSplicing ctx <- Quill.Postgres(Literal, connectionPool) with AstSplicing // Then run a query and invoke getLastExecutionInfo people <- ctx.run(quote { query[Person] }) info <- ctx.getLastExecutionInfo() _ <- ZIO.log(s"Last Executed Ast: ${info.ast}") } yield people ``` -------------------------------- ### Batch Insert with Different Entities Source: https://github.com/zio/zio-protoquill/blob/master/README.md Perform batch inserts using `liftQuery` and `foreach`. This example inserts `Person` records from a list of VIP data. ```scala liftQuery(vips).foreach(v => query[Person].insertValue(Person(v.first + v.last, v.age))) ``` -------------------------------- ### Testing Batch Insert Operations with Mirror Context Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/mirror-context.md Shows how to test batch insert operations using MirrorContext. This example inserts multiple records defined in a list. ```scala val ctx = new MirrorContext(PostgresDialect, SnakeCase) import ctx._ val people = List(Person(1, "Alice"), Person(2, "Bob")) inline def batchInsert = quote { liftQuery(people).foreach(p => query[Person].insertValue(p)) } val result = ctx.run(batchInsert, 10) println(result.sql) ``` -------------------------------- ### Complete GraphQL Integration Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/caliban-integration.md This Scala code demonstrates a full integration of Caliban with ZIO and Quill for a PostgreSQL database. It sets up a data context, defines queries, creates a GraphQL schema, and configures an HTTP server. ```scala import io.getquill._ import io.getquill.CalibanIntegration._ import caliban._ import caliban.schema.Annotations._ import zio._ import zio.http._ import zio.http.Server case class Person(id: Int, firstName: String, lastName: String, age: Int) case class Address(personId: Int, street: String, city: String) case class PersonAddress( id: Int, firstName: String, lastName: String, age: Int, street: Option[String] ) case class ProductArgs( firstName: Option[String] = None, lastName: Option[String] = None, age: Option[Int] = None, street: Option[String] = None ) { def keyValues: Map[String, String] = { val m = scala.collection.mutable.Map[String, String]() firstName.foreach(v => m("firstName") = v) lastName.foreach(v => m("lastName") = v) age.foreach(v => m("age") = v.toString) street.foreach(v => m("street") = v) m.toMap } } // Setup context val ctx = new PostgresJdbcContext(Literal, "ctx") import ctx._ // Define base query inline def peopleAndAddresses( inline columns: List[String], inline filters: Map[String, String] ) = quote { query[Person] .leftJoin(query[Address]) .on((p, a) => p.id == a.personId) .map((p, a) => PersonAddress(p.id, p.firstName, p.lastName, p.age, a.map(_.street))) .filterColumns(columns) .filterByKeys(filters) } // Data service object DataService { def personAddress(columns: List[String], filters: Map[String, String]) = ctx.run(peopleAndAddresses(columns, filters)) } // GraphQL Schema case class Queries( personAddress: Field => (ProductArgs => Task[List[PersonAddress]]) ) // Resolver val api = graphQL( RootResolver( Queries( personAddress => args => ZIO.attempt { DataService.personAddress( quillColumns(personAddress), args.keyValues ) }.mapError(_.getMessage) ) ).interpreter // HTTP Server object CalibanExample extends ZIOAppDefault { val routes = Http.route { case _ -> Root / "api" / "graphql" => ZHttpAdapter.makeHttpService(api) } override def run = Server.serve(routes).provide(Server.default) } ``` -------------------------------- ### Integrating Caliban Endpoint with ZIO-Http Source: https://github.com/zio/zio-protoquill/blob/master/README.md Shows how to integrate the Caliban GraphQL endpoint into a ZIO-Http server. This example assumes the existence of `Dao.resetDatabase()` and `endpoints`. ```scala object CalibanExample extends zio.App: val myApp = for { _ <- Dao.resetDatabase() interpreter <- endpoints _ <- Server.start( port = 8088, http = Http.route { case _ -> Root / "api" / "graphql" => ZHttpAdapter.makeHttpService(interpreter) } ) .forever } yield () override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] = myApp.exitCode end CalibanExample ``` -------------------------------- ### Batch Operation Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Demonstrates performing batch operations by executing multiple similar statements together for improved efficiency. The `liftQuery` function is used to embed a collection of values, and a batch size can be specified. ```scala inline def batch = quote { liftQuery(people).foreach(p => query[Person].insertValue(p)) } val results = ctx.run(batch, 25) // 25 statements per batch ``` -------------------------------- ### Batch Insert with Returning Clause Source: https://github.com/zio/zio-protoquill/blob/master/README.md Execute batch inserts and retrieve generated IDs using the `returning` clause. This example inserts VIPs and returns their new IDs. ```scala liftQuery(vips).foreach(v => query[Person].insertValue(Person(v.first + v.last, v.age)).returning(_.id)) ``` -------------------------------- ### Testing Nested Queries with Mirror Context Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/mirror-context.md Illustrates testing nested queries using MirrorContext. The example shows filtering on a nested query result. ```scala inline def nestedQuery = quote { query[Person] .filter(_.age > 25) .map(p => (p.id, p.name)) .nested .filter { case (id, _) => id > 10 } } println(ctx.run(nestedQuery).sql) ``` -------------------------------- ### Lazy Lifting Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Shows how to use `lazyLift` to defer encoder summoning until runtime. This is useful when the same query needs to be used with different contexts that might have different encoder implementations. ```scala inline def query = quote { query[Person].filter(_.name == lazyLift(runtimeName)) } // Can be used with multiple contexts val pgResult = pgContext.run(query) val mysqlResult = mysqlContext.run(query) ``` -------------------------------- ### Batch Update with Scalars Source: https://github.com/zio/zio-protoquill/blob/master/README.md Execute batch updates on multiple records using `liftQuery` and `foreach`. This example updates the age of people with specific IDs. ```scala liftQuery(List(1,2,3)).foreach(i => query[Person].filter(p => p.id == i).update(_.age -> 123)) ``` -------------------------------- ### Batch Update with Additional Lifts Source: https://github.com/zio/zio-protoquill/blob/master/README.md Perform batch updates with multiple `lift` and `liftQuery` clauses. This example updates people's ages based on a condition and a list of IDs. ```scala liftQuery(people).foreach(p => query[Person].filter(p => p.age > lift(123)).contains(p.age)).updateValue(p)) ``` -------------------------------- ### GraphQL Query Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/caliban-integration.md This GraphQL query demonstrates filtering and column selection. It requests specific fields for person addresses and filters by first name, allowing the database to optimize the query. ```graphql query { personAddress(firstName: "Alice") { id firstName lastName street } } ``` -------------------------------- ### Stop Services (Preserving Volumes) Source: https://github.com/zio/zio-protoquill/blob/master/build/m1/README.MD Use this command to stop your services without removing the created volumes, which preserves the database setup for rapid build/test cycles. Uses the `docker-compose-m1.yml` file. ```bash docker compose -f docker-compose-m1.yml stop ``` -------------------------------- ### Unsupported Implicit Extension Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/extensions-custom-parsing.md Illustrates an implicit class extension for `Person` that is not yet supported in ProtoQuill's compile-time quotations. Using such extensions can lead to dynamic query detection issues. ```scala // NOT SUPPORTED (yet) implicit class PersonExt(p: Person) { def fullName = p.first + " " + p.last } ``` -------------------------------- ### Build with Specific Scala Version Source: https://github.com/zio/zio-protoquill/blob/master/build/m1/README.MD Specify a custom Scala version for the build by setting the `quill.scala.version` property. This example uses Scala 2.13.6 and includes the `db` module tests. ```bash docker compose -f docker-compose-m1.yml run sbt sbt -Dquill.scala.version=2.13.6 -Dmodules=db test ``` -------------------------------- ### Provide Data Source Layer at Entry Point Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-zio.md Demonstrates providing the `dataSourceLayer` at the entry point of a ZIO application using `ZIOAppDefault`. This ensures the data source is available for all subsequent ZIO effects. ```scala object Main extends ZIOAppDefault { val dataSourceLayer = // ... create layer val program = for { result <- myQueries } yield result def run = program.provideLayer(dataSourceLayer) } ``` -------------------------------- ### Basic Compile-Time Query with PostgresJdbcContext Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/00_START_HERE.md Demonstrates how to set up a PostgresJdbcContext, define a case class, write a compile-time query using inline quotations, and execute it. ```scala import io.getquill.* case class Person(id: Int, name: String, age: Int) val ctx = new PostgresJdbcContext(SnakeCase, "ctx") import ctx._ // Compile-time query inline def adults = quote { query[Person].filter(_.age >= 18) } // Execute val people: List[Person] = ctx.run(adults) ``` -------------------------------- ### Testing Caliban Endpoint with GraphQL Query Source: https://github.com/zio/zio-protoquill/blob/master/README.md Provides an example of a Caliban GraphQL query string to test the `personAddressFlat` endpoint. Allows filtering by fields like 'first' and selecting specific fields like 'id', 'last', and 'street'. ```scala // Test-run the endpoint like this! (make sure not use the 'query' variable or it will collide with Quill!): val calibanQuery = """ { # Filter by any field in PersonAddress here including first, last, age, street! (or any combination of filters!) personAddressFlat(first: "Joe") { # Include/Exclude any fields from PersonAddress here! id last street } }""" val output = zio.Runtime.default.unsafeRun(for { interpreter <- api.interpreter result <- interpreter.execute(calibanQuery) } yield (result) ) // The following data will be returned: output.data.toString == "{"personAddress":[{"id":1,"first":"One","last":"A","street":"123 St"}]}" ``` -------------------------------- ### Example Usage of Quoted Type Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/query-execution.md Demonstrates how to create a Quoted object for a query that filters persons by age. ```scala val quoted: Quoted[Query[Person]] = quote { query[Person].filter(_.age > 30) } ``` -------------------------------- ### Delete Action Definition and Usage Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/query-execution.md Represents a DELETE statement. Includes an example for deleting rows based on a filter condition. ```scala sealed trait Delete[T] extends Action[T] ``` ```scala inline def deleteOldPeople = quote { query[Person].filter(_.age > 100).delete } val rowsDeleted = ctx.run(deleteOldPeople) ``` -------------------------------- ### Define a Filtered Inline Query Source: https://github.com/zio/zio-protoquill/blob/master/README.md Define a filtered query using `inline def`. This example filters for people named 'Joe'. ```scala inline def joes = quote { people.filter(p => p.name == "Joe") } ``` -------------------------------- ### Batch Inserts with ProtoQuill Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/00_START_HERE.md Demonstrates how to perform efficient bulk inserts using ProtoQuill's batching capabilities. Specify the batch size when running the query. ```scala inline def batch = quote { liftQuery(people).foreach(p => query[Person].insertValue(p)) } val results = ctx.run(batch, 25) // 25 rows per batch ``` -------------------------------- ### Define an Inline Query Source: https://github.com/zio/zio-protoquill/blob/master/README.md Define a query using `inline def` for compile-time query generation. This example defines a query for all people. ```scala inline def people = quote { query[Person] } ``` -------------------------------- ### Nullable Equality Usage Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/quotation-dsl.md Demonstrates how to use the null-safe equality operator (===) with an optional value in a Quill query filter. ```scala import io.getquill.* import io.getquill.extras._ inline def query = quote { query[Person].filter(p => p.name === lift(optionalName)) } ``` -------------------------------- ### Comparing SQL Dialects with MirrorContext Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/mirror-context.md Illustrates how to compare SQL generation across different dialects (PostgreSQL, MySQL, SQL Server) using MirrorContext. ```scala val pgCtx = new MirrorContext(PostgresDialect, SnakeCase) val mysqlCtx = new MirrorContext(MySQLDialect, SnakeCase) val mssqlCtx = new MirrorContext(SqlServerDialect, SnakeCase) import pgCtx._ inline def myQuery = quote { query[Person].filter(_.age > 30) } println("PostgreSQL: " + pgCtx.run(myQuery).sql) println("MySQL: " + mysqlCtx.run(myQuery).sql) println("SQL Server: " + mssqlCtx.run(myQuery).sql) ``` -------------------------------- ### Import ProtoQuill for Quotations Source: https://github.com/zio/zio-protoquill/blob/master/README.md Import `io.getquill._` to use `quote`, `query`, `insert/update/delete`, and `lazyLift` in your ProtoQuill code. ```scala // With just this import you can use quote, query, insert/update/delete and lazyLift import io.getquill._ ``` -------------------------------- ### Update Action Definition and Usage Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/query-execution.md Represents an UPDATE statement. Includes examples for updating specific columns and returning updated values. ```scala sealed trait Update[T] extends Action[T] ``` ```scala def returning[R](f: T => R): ActionReturning[T, R] ``` ```scala inline def updateAge = quote { query[Person].filter(_.name == lift("Alice")).update(_.age -> 26) } val rowsUpdated = ctx.run(updateAge) // With returning inline def updateAndReturn = quote { query[Person] .filter(_.name == lift("Alice")) .update(_.age -> 26) .returning(_.id) } val updatedId = ctx.run(updateAndReturn) ``` -------------------------------- ### Using lift with a Context Source: https://github.com/zio/zio-protoquill/blob/master/README.md Demonstrates the correct order of importing a context and then using the `lift` method within a quoted query. This is essential for ProtoQuill's value lifting mechanism. ```scala // Must do this: val ctx = new MyDatabaseContext() import ctx._ // Before Doing this: inline def somePeople = quote { query[Person].filter(p => p.name == lift(runtimeValue)) } ``` -------------------------------- ### Compile and Test (all tests) Source: https://github.com/zio/zio-protoquill/blob/master/build/m1/README.MD Run this command to execute all tests, including codegen tests. This process can be lengthy. Uses the `docker-compose-m1.yml` file. ```bash docker compose -f docker-compose-m1.yml run sbt sbt test ``` -------------------------------- ### Query Macro Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/quotation-dsl.md Creates an EntityQuery representing a base query over type T, used to start building SQL queries from case classes. ```scala inline def query[T]: EntityQuery[T] ``` ```scala case class Person(id: Int, name: String, age: Int) inline def allPeople = quote { query[Person] } // Can be used in filters, maps, joins, etc. inline def adults = quote { query[Person].filter(p => p.age >= 18) } ``` -------------------------------- ### Importing ProtoQuill Components Source: https://github.com/zio/zio-protoquill/blob/master/README.md In ProtoQuill, core methods like 'query' and 'quote' come from the 'io.getquill.Dsl' object. Ensure you import at least 'io.getquill.quote' and 'io.getquill.query'. ```scala import io.getquill.quote import io.getquill.query ``` -------------------------------- ### Inline Quotation Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Defines an inline quotation for filtering people aged 18 or older. The `inline` keyword ensures compile-time processing. ```scala inline def adults = quote { query[Person].filter(_.age >= 18) } ``` -------------------------------- ### Batch Query Structure Source: https://github.com/zio/zio-protoquill/wiki/Design-Info:-Batch-Query-Execution Illustrates the basic structure of a batch query using liftQuery and foreach. ```scala liftQuery(people).foreach(p => query[Person].insert(p)) // Foreach(lift(entities), Ident("p"), { Insert(CaseClass(...)) }) ``` -------------------------------- ### Defining a Join Query Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/query-execution.md Example of defining a join between two tables, Person and Address. The join condition is specified using the .on() method. ```scala inline def personAddressJoin = quote { query[Person] .join(query[Address]) .on((p, a) => p.id == a.personId) } ``` -------------------------------- ### Testing Query Generation with MirrorContext Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/mirror-context.md Shows how to test query generation using MirrorContext with joins and projections. Imports are required. ```scala val ctx = new MirrorContext(PostgresDialect, Literal) import ctx._ case class Order(id: Int, customerId: Int, total: BigDecimal) case class Customer(id: Int, name: String) inline def ordersByCustomer = quote { query[Order] .join(query[Customer]).on((o, c) => o.customerId == c.id) .map((o, c) => (c.name, o.total)) } val result = ctx.run(ordersByCustomer) println(result.sql) // SELECT c.name, o.total FROM order o // INNER JOIN customer c ON o.customer_id = c.id ``` -------------------------------- ### JDBC Context Configuration Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Shows how to configure a synchronous JDBC context for PostgreSQL using an application.conf file. The context is initialized with a naming strategy and a configuration key. ```properties # application.conf postgres.dataSourceClassName = org.postgresql.ds.PGSimpleDataSource postgres.dataSource.url = jdbc:postgresql://localhost:5432/mydb postgres.dataSource.user = dbuser postgres.dataSource.password = dbpass ``` ```scala val ctx = new PostgresJdbcContext(SnakeCase, "postgres") ``` -------------------------------- ### Configure PostgreSQL Datasource in application.conf Source: https://github.com/zio/zio-protoquill/blob/master/README.md Add this configuration to your application.conf file to set up a PostgreSQL data source for testing. ```scala testPostgresDB.dataSourceClassName=org.postgresql.ds.PGSimpleDataSource testPostgresDB.dataSource.databaseName= testPostgresDB.dataSource.url= ``` -------------------------------- ### Insert Action Definition and Usage Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/query-execution.md Represents an INSERT statement. Includes examples for simple inserts, inserts with returning clauses, and returning generated IDs. ```scala sealed trait Insert[T] extends Action[T] ``` ```scala def returning[R](f: T => R): ActionReturning[T, R] ``` ```scala def returningGenerated[R](f: T => R): ActionReturning[T, R] ``` ```scala def onConflictIgnore: Insert[T] ``` ```scala def onConflictUpdate[T](f: (T, T) => (T => (Any, Any))*): Insert[T] ``` ```scala case class Person(id: Int, name: String, age: Int) val ctx = new PostgresJdbcContext(Literal, "ctx") import ctx._ inline def insertPerson = quote { query[Person].insertValue(lift(Person(0, "Alice", 25))) } // Simple insert val rowsInserted = ctx.run(insertPerson) // Insert with returning inline def insertWithId = quote { query[Person].insertValue(lift(Person(0, "Bob", 30))).returning(_.id) } val newId = ctx.run(insertWithId) ``` -------------------------------- ### Add Cassandra Dependencies Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Include the Cassandra module for synchronous access and the ZIO-based Cassandra module for asynchronous operations with ZIO. ```scala libraryDependencies += "io.getquill" %% "quill-cassandra" % "4.7.3" libraryDependencies += "io.getquill" %% "quill-cassandra-zio" % "4.7.3" ``` -------------------------------- ### Custom Parsing with Quoted Expressions Source: https://github.com/zio/zio-protoquill/blob/master/README.md Define extension methods for quoted expressions to use custom logic within queries. This example shows a power function. ```scala import io.getquill._ object MyBusinessLogic: extension (inline i: Int) inline def ** (exponent: Int) = quote { sql"power($i, $exponent)" } def main(args: Array[String]) = import MyBusinessLogic._ run( query[Person].map(p => p.age ** 2 ) // SELECT power(p.age, 2) FROM Person p ``` -------------------------------- ### Typeclass for Filterable Collections in ProtoQuill Source: https://github.com/zio/zio-protoquill/blob/master/README.md Generalize shared code constructs into typeclasses for higher-level abstractions. This example demonstrates a `Filterable` typeclass for both `List` and Quill `Query`. ```scala // case class Person(name: String, age: Int) trait Filterable[F[_]]: extension [A](inline x: F[A]) inline def filter(inline f: A => Boolean): F[A] extension [F[_]](inline people: F[Person])(using inline filterable: Filterable[F]) inline def onlyJoes = people.filter(p => p.name == "Joe") class ListFilterable extends Filterable[List]: extension [A](inline xs: List[A]) inline def filter(inline f: A => Boolean): List[A] = xs.filter(f) class QueryFilterable extends Filterable[List]: extension [A](inline xs: List[A]) inline def filter(inline f: A => Boolean): List[A] = xs.filter(f) run( query[Person].onlyJoes ) // GET SQL val people: List[Person] = ... val joes = people.onlyJoes ``` -------------------------------- ### Define Case Class and JDBC Context Source: https://github.com/zio/zio-protoquill/blob/master/README.md Create a case class for your data model and instantiate a PostgresJdbcContext. This example uses SnakeCase for column name conversion. ```scala import io.getquill._ object MyApp { case class Person(firstName: String, lastName: String, age: Int) // SnakeCase turns firstName -> first_name val ctx = new PostgresJdbcContext(SnakeCase, "ctx") import ctx._ def main(args: Array[String]): Unit = { val named = "Joe" inline def somePeople = quote { query[Person].filter(p => p.firstName == lift(named)) } val people: List[Person] = run(somePeople) // TODO Get SQL println(people) } } ``` -------------------------------- ### Testing Aggregate Queries with Mirror Context Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/mirror-context.md Demonstrates how to test aggregate queries using MirrorContext. Ensure the necessary case classes and context imports are defined. ```scala case class Order(customerId: Int, amount: BigDecimal) val ctx = new MirrorContext(PostgresDialect, SnakeCase) import ctx._ inline def totalByCustomer = quote { query[Order] .groupBy(_.customerId) .map { case (customerId, orders) => (customerId, orders.map(_.amount).sum) } } println(ctx.run(totalByCustomer).sql) ``` -------------------------------- ### Array Encoding/Decoding (JDBC) Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/encoders-decoders.md Provides generic encoders and decoders for Array types in JDBC. The example demonstrates how to insert an array of strings into a Tags case class. ```scala implicit def arrayEncoder[T](implicit enc: GenericEncoder[T, _, _]): GenericEncoder[Array[T], PreparedStatement, Connection] implicit def arrayDecoder[T](implicit dec: GenericDecoder[ResultSet, Connection, T, _]): GenericDecoder[ResultSet, Connection, Array[T], Generic] ``` ```scala case class Tags(id: Int, items: Array[String]) inline def insert = quote { query[Tags].insertValue(lift(Tags(1, Array("a", "b", "c")))) } ``` -------------------------------- ### ProtoQuill Module Dependencies Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/00_START_HERE.md Lists the necessary library dependencies for using ProtoQuill with different backends like JDBC, ZIO, and Cassandra. Add these to your project's build file. ```scala // Core SQL libraryDependencies += "io.getquill" %% "quill-sql" % "4.7.3" // JDBC libraryDependencies += "io.getquill" %% "quill-jdbc" % "4.7.3" libraryDependencies += "io.getquill" %% "quill-jdbc-zio" % "4.7.3" // Cassandra libraryDependencies += "io.getquill" %% "quill-cassandra" % "4.7.3" libraryDependencies += "io.getquill" %% "quill-cassandra-zio" % "4.7.3" // GraphQL libraryDependencies += "io.getquill" %% "quill-caliban" % "4.7.3" ``` -------------------------------- ### Mirror Context for Testing Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Illustrates using a MirrorContext for testing ProtoQuill queries without a live database. This context translates queries to SQL strings. ```scala val ctx = new MirrorContext(PostgresDialect, SnakeCase) import ctx._ inline def query = quote { query[Person].filter(_.age > 30) } val result = ctx.run(query) println(result.sql) // SELECT p.id, p.name, p.age FROM person p WHERE p.age > ? ``` -------------------------------- ### Using lazyLift Source: https://github.com/zio/zio-protoquill/blob/master/README.md Shows how to use `lazyLift` which delays summoning the encoder until the `run` function. A context is only needed for the `run` function itself. ```scala inline def somePeople = quote { query[Person].filter(p => p.name == lazyLift(runtimeValue)) } // Need to import a context only for the `run` function. val ctx = new MyDatabaseContext() import ctx._ val result: List[Person] = run(somePeople) // summons Encoder[String] here ``` -------------------------------- ### PostgresJdbcZioContext Run Methods Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-zio.md Provides the asynchronous run methods for executing queries and actions against a PostgreSQL database using ZIO. ```scala inline def run[T](inline quoted: Quoted[Query[T]]): ZIO[Has[DataSource], SQLException, List[T]] inline def run[T](inline quoted: Quoted[T]): ZIO[Has[DataSource], SQLException, T] inline def run[E](inline quoted: Quoted[Action[E]]): ZIO[Has[DataSource], SQLException, Long] inline def run[E, T](inline quoted: Quoted[ActionReturning[E, T]]): ZIO[Has[DataSource], SQLException, T] inline def run[I, A <: Action[I] & QAC[I, Nothing]]( inline quoted: Quoted[BatchAction[A]], rowsPerBatch: Int ): ZIO[Has[DataSource], SQLException, List[Long]] ``` -------------------------------- ### Case Class Encoding/Decoding (JDBC) Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/encoders-decoders.md Case classes are automatically encoded and decoded for JDBC operations through generic derivation. This example shows inserting and querying Person objects. ```scala case class Person(id: Int, name: String, age: Int) // Automatically summoned: // GenericEncoder[Person, PreparedStatement, Connection] // GenericDecoder[ResultSet, Connection, Person, Generic] ``` ```scala val ctx = new PostgresJdbcContext(Literal, "ctx") import ctx._ case class Person(id: Int, name: String, age: Int) inline def insertPerson = quote { query[Person].insertValue(lift(Person(0, "Alice", 25))) } // Person is automatically encoded to prepared statement parameters val id = ctx.run(insertPerson) inline def allPeople = quote { query[Person] } // Rows are automatically decoded to List[Person] val people = ctx.run(allPeople) ``` -------------------------------- ### Original SQL Query Source: https://github.com/zio/zio-protoquill/blob/master/README.md This is the base SQL query before any transformations are applied by zio-protoquill's filtering methods. ```sql SELECT p.id, p.first, p.last, p.age, a.street FROM Person p LEFT JOIN Address a ON p.id = a.ownerId ``` -------------------------------- ### Module Conflict Error Example Source: https://github.com/zio/zio-protoquill/wiki/FAQ This error indicates conflicting cross-version suffixes for modules. It occurs when different versions of libraries are required for Scala 3 and Scala 2.13. ```text Modules were resolved with conflicting cross-version suffixes [error] com.lihaoyi:sourcecode _3, _2.13 [error] com.lihaoyi:fansi _3, _2.13 [error] com.lihaoyi:pprint _3, _2.13 ``` ```text [error] Modules were resolved with conflicting cross-version suffixes in ProjectRef(uri("file:/Volumes/Personal/projects/full-zio-stack/"), "server"): [error] org.scala-lang.modules:scala-collection-compat _3, _2.13 ``` -------------------------------- ### Execution Info with AST Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/advanced-features.md Obtain detailed execution information including the query string, prepared statement, parameters, and the Abstract Syntax Tree (AST). Requires extending `AstSplicing`. ```scala trait AstSplicing { def getLastExecutionInfo(): Result[ExecutionInfo] } case class ExecutionInfo( queryString: String, preparedStatement: String, params: Seq[String], ast: Ast // With AstSplicing ) ``` -------------------------------- ### Batch Insert and Update Operations Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/query-execution.md Demonstrates how to perform batch inserts and updates using ProtoQuill. Specify the number of rows per batch as the second argument to ctx.run(). ```scala case class Person(id: Int, name: String) val ctx = new PostgresJdbcContext(Literal, "ctx") import ctx._ val people = List( Person(1, "Alice"), Person(2, "Bob"), Person(3, "Charlie") ) // Batch insert inline def batchInsert = quote { liftQuery(people).foreach(p => query[Person].insertValue(p)) } val results = ctx.run(batchInsert, 10) // 10 rows per batch // Batch update with additional lifts val ageThreshold = 25 inline def batchUpdate = quote { liftQuery(people).foreach(p => query[Person] .filter(_.id == p.id) .filter(_.age > lift(ageThreshold)) .update(_.name -> p.name) ) } val updateResults = ctx.run(batchUpdate, 5) ``` -------------------------------- ### Get Last Executed Query (ZIO) Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/advanced-features.md Retrieve the last executed SQL query string when using ZIO contexts. This is helpful for debugging and understanding the queries being generated. ```scala val ctx = new PostgresJdbcZioContext(Literal, dataSourceLayer) import ctx._ val program = for { people <- ctx.run(quote { query[Person] }) query <- ctx.getLastExecutedQuery() _ <- ZIO.debug(s"Last query: $query") } yield people ``` -------------------------------- ### Conceptual SQL Generation for filterByKeys Source: https://github.com/zio/zio-protoquill/blob/master/README.md Illustrates the conceptual SQL generation for `filterByKeys`, showing how map values are substituted into the WHERE clause. ```sql // SELECT p.firstName, p.lastName, p.age // FROM Person p // WHERE // (p.firstName = { values("firstName") } OR { values("firstName") } IS NULL) AND // (p.lastName = { values("lastName") } OR { values("lastName") } IS NULL) AND // (p.age = { values("age") } OR { values("age") } IS NULL) AND // true ``` -------------------------------- ### Run a Query with Dynamic Parts Requiring Quotation Source: https://github.com/zio/zio-protoquill/blob/master/README.md When parts of a query are dynamic (not `inline def`), quotation is required. This example shows a dynamic query for people named 'Joe'. ```scala val joes = quote { people.filter(p => p.name == "Joe") } run(joes) // TODO Warning Dynamic Query ``` -------------------------------- ### Dynamic Query Building with Optional Filters Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/README.md Demonstrates dynamic query construction in ProtoQuill using `DynamicQuery` and applying optional filters based on provided values. ```scala val minAge: Option[Int] = Some(25) val nameFilter: Option[String] = None val q = DynamicQuery(quote { query[Person] }) .filterOpt(minAge)((p, age) => p.age > lift(age)) .filterOpt(nameFilter)((p, name) => p.name == lift(name)) val results = ctx.run(q.q) ``` -------------------------------- ### Collection Encoding Example Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/cassandra-context.md Illustrates how Quill automatically encodes Scala collection types like Set[String] to their corresponding Cassandra CQL types (e.g., set). ```scala case class Tag(id: String, tags: Set[String]) // Quill automatically encodes Set[String] to CQL set inline def query = quote { query[Tag].filter(_.tags.contains(lift("popular"))) } ``` -------------------------------- ### Mirror Context Methods Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/DOCUMENTATION_INDEX.md Describes the MirrorContext for SQL generation and testing without actual query execution, returning SQL and results. ```APIDOC ## Mirror Context (mirror-context.md): - `MirrorContext[Dialect, Naming]` - Returns: `QueryResult[T]` with SQL and value ``` -------------------------------- ### Compose Queries for Sequential Operations Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/context-zio.md Shows how to compose multiple Quill queries sequentially within a ZIO `for` comprehension. This allows for complex data retrieval and processing workflows. ```scala val program = for { person <- ctx.run(findPerson) orders <- ctx.run(findOrdersForPerson(person.id)) _ <- ZIO.logInfo(s"${person.name} has ${orders.length} orders") } yield () ``` -------------------------------- ### Using Custom Parser in Application Code Source: https://github.com/zio/zio-protoquill/blob/master/_autodocs/extensions-custom-parsing.md Demonstrates how to use a custom parser in a separate project that depends on the project defining the custom logic and parser. It shows a ProtoQuill query using the custom '**' operator, which is translated to 'power()'. ```scala // In second project (depends on first) given myParser: CustomParser.type = CustomParser import MyBusinessLogic._ case class Person(name: String, age: Int) inline def q = quote { query[Person].map(p => p.age ** 2) } // Generates: SELECT power(p.age, 2) FROM person p ```