### Verify Database Setup with SQL Query Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/01-Introduction.md A sample SQL query to run against the 'world' database to verify the setup. This query selects country names, continents, and populations for countries starting with 'U'. ```sql psql -d world -U postgres world=> select name, continent, population from country where name like 'U%'; ``` -------------------------------- ### Start Docker Compose for Doobie Development Source: https://github.com/typelevel/doobie/blob/main/CONTRIBUTING.md Use this command to spin up the necessary Docker containers for running tests and building the documentation site. Ensure Docker is installed and running. ```bash docker compose up -d --force-recreate ``` -------------------------------- ### Setup Sample Database with SQL Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/01-Introduction.md Commands to set up a local PostgreSQL server with the sample 'world' database, user, and necessary extensions. Adjust connection details if your setup differs. ```bash $ curl -O https://raw.githubusercontent.com/typelevel/doobie/series/0.7.x/world.sql $ psql -c 'create user postgres createdb' postgres $ psql -c 'create database world;' -U postgres $ psql -c '\i world.sql' -d world -U postgres $ psql -d world -c "create type myenum as enum ('foo', 'bar')" -U postgres $ psql -d world -c "create extension postgis" -U postgres ``` -------------------------------- ### Setup PostgreSQL Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Configure a Transactor for PostgreSQL connections using DriverManager. This example uses a synchronous EC for blocking operations. ```scala import cats._ import cats.data._ import cats.effect._ import cats.implicits._ import doobie._ import doobie.implicits._ import doobie.util.ExecutionContexts // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[ IO ]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) ``` -------------------------------- ### Setting Up doobie Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/04-Selecting.md Imports and Transactor setup for database operations. This is boilerplate for most doobie examples. ```scala import doobie._ import doobie.implicits._ import doobie.util.ExecutionContexts import cats._ import cats.data._ import cats.effect._ import cats.implicits._ import fs2.Stream // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) ``` ```scala implicit val mdocColors: doobie.util.Colors = doobie.util.Colors.None ``` -------------------------------- ### H2 Connection Pool Setup Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/16-Extensions-H2.md Demonstrates setting up an H2 Transactor with a fixed thread pool for connections and an unbounded pool for transactions. This setup ensures clean resource management. ```scala import cats.effect._ import cats.implicits._ import doobie._ import doobie.implicits._ import doobie.h2._ object H2App extends IOApp { // Resource yielding a transactor configured with a bounded connect EC and an unbounded // transaction EC. Everything will be closed and shut down cleanly after use. val transactor: Resource[IO, H2Transactor[IO]] = for { ce <- ExecutionContexts.fixedThreadPool[IO](32) // our connect EC xa <- H2Transactor.newH2Transactor[IO]( "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", // connect URL "sa", // username "", // password ce, // await connection here ) } yield xa def run(args: List[String]): IO[ExitCode] = transactor.use { xa => // Construct and run your server here! for { n <- sql"select 42".query[Int].unique.transact(xa) _ <- IO(println(n)) } yield ExitCode.Success } } ``` -------------------------------- ### Running HikariCP Example Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md This is how you would typically run the HikariCP application defined above. ```scala HikariApp.main(Array()) ``` -------------------------------- ### Correct way to request Get and Put Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Illustrates the correct way to request `Get` and `Put` instances in user code. Avoid requesting `Meta` directly; instead, request `Get`, `Put`, or both as needed. ```scala def foo[A: Meta](...) // don't do this def foo[A: Get: Put](...) // ok ``` -------------------------------- ### Building the Doc Site with sbt Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/index.md Commands to clean, build, and deploy the documentation site using sbt. Ensure you are in the project root and have sbt installed. ```shell % sbt sbt:doobie> project docs sbt:docs> clean sbt:docs> makeSite sbt:doce> ghpagesPushSite ``` -------------------------------- ### Setup Transactor for PostgreSQL Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/17-FAQ.md Sets up a Transactor for PostgreSQL using DriverManager. This is for testing purposes; consider using IOApp for production. ```scala import cats._ import cats.data._ import cats.effect._ import cats.effect.implicits._ import cats.implicits._ import doobie._ import doobie.implicits._ import doobie.util.ExecutionContexts import java.awt.geom.Point2D import java.util.UUID import shapeless._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager. // See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) ``` -------------------------------- ### Setup Imports for Logging Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/10-Logging.md Imports required for setting up logging and transactors in doobie. ```scala import doobie._ import doobie.implicits._ import doobie.util.log.LogEvent import cats.effect._ import cats.implicits._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global ``` -------------------------------- ### Scala Project Setup with Doobie Dependencies Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/01-Introduction.md A minimal build.sbt file to include Doobie core, PostgreSQL, and Specs2 dependencies. Ensure you have the correct Scala version and Doobie version specified. ```scala scalaVersion := "$scalaVersion$" // Scala $scalaVersion$ lazy val doobieVersion = "$version$" libraryDependencies ++= Seq( "org.tpolecat" %% "doobie-core" % doobieVersion, "org.tpolecat" %% "doobie-postgres" % doobieVersion, "org.tpolecat" %% "doobie-specs2" % doobieVersion ) ``` -------------------------------- ### Attempting a Query with doobie Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Demonstrates a basic query that is expected to fail, setting up for error handling examples. ```scala val p = sql"oops".query[String].unique // this won't work ``` -------------------------------- ### Setting up doobie Transactor and Imports Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/11-Arrays.md Configure a transactor for PostgreSQL and import necessary doobie modules for array support. This setup is for testing purposes; consider using `IOApp` for production. ```scala import doobie._ import doobie.implicits._ import doobie.postgres._ import doobie.postgres.implicits._ import doobie.util.ExecutionContexts import cats._ import cats.data._ import cats.effect._ import cats.implicits._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) val y = xa.yolo import y._ ``` ```scala implicit val mdocColors: doobie.util.Colors = doobie.util.Colors.None ``` -------------------------------- ### Setup Imports and Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/06-Checking.md Imports necessary doobie and Cats Effect libraries, and configures a Transactor for database connections using DriverManager. YOLO mode is enabled for query checking. ```scala import doobie._ import doobie.implicits._ import doobie.util.ExecutionContexts import cats._ import cats.data._ import cats.effect._ import cats.implicits._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) val y = xa.yolo import y._ ``` ```scala implicit val mdocColors: doobie.util.Colors = doobie.util.Colors.None ``` -------------------------------- ### Basic Transactor and Query Setup Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/index.md Defines a transactor for database connections and a query to retrieve country data. Requires Cats Effect for IO and doobie implicits. ```scala import doobie._ import doobie.implicits._ import cats.effect.IO import scala.concurrent.ExecutionContext import cats.effect.unsafe.implicits.global val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", url = "jdbc:postgresql:world", user = "postgres", password = "password", logHandler = None ) case class Country(code: String, name: String, population: Long) def find(n: String): ConnectionIO[Option[Country]] = sql"select code, name, population from country where name = $n".query[Country].option ``` -------------------------------- ### Derive Get and Put for Nat using .map and .contramap Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Creates `Get` and `Put` instances for the `Nat` type by leveraging the existing `Get[Int]` and `Put[Int]` instances. This approach uses the `Functor` and `Contravariant` capabilities of `Get` and `Put` respectively. ```scala // Bidirectional schema mapping for Nat, in terms of Int implicit val natGet: Get[Nat] = Get[Int].map(fromInt) implicit val natPut: Put[Nat] = Put[Int].contramap(toInt) ``` -------------------------------- ### ResultSetOp Constructor Example Source: https://github.com/typelevel/doobie/wiki/Low-Level-API Illustrates the mapping of a Java ResultSet method to a Scala ResultSetOp constructor. This pattern applies to all methods in the ResultSetOp algebra. ```java int findColumn(String columnLabel) // Java instance method ``` ```scala case class FindColumn(a: String) extends ResultSetOp[Int] ``` -------------------------------- ### Run EXPLAIN ANALYZE on a PostgreSQL Query with doobie Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Use the `.explainAnalyze` method to get query plan analysis and actual execution performance. Requires `doobie.postgres._` and `doobie.postgres.implicits._` imports. Returns a `ConnectionIO[List[String]]`. ```scala import doobie.implicits._ import doobie.postgres.implicits._ sql"select name from country" .query[String] // Query0[String] .explainAnalyze .transact(xa) .unsafeRunSync() .foreach(println) ``` -------------------------------- ### Derive Get and Put for Nat using .tmap and .tcontramap Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Defines `Get` and `Put` instances for `Nat` using `.tmap` and `.tcontramap`. These methods are preferred over `.map` and `.contramap` as they incorporate `TypeTag`s, potentially leading to better diagnostic messages from the query checker. ```scala // Prefer .tmap and .tcontramap when possible. implicit val natGet2: Get[Nat] = Get[Int].tmap(fromInt) implicit val natPut2: Put[Nat] = Put[Int].tcontramap(toInt) ``` -------------------------------- ### Example of Non-Compiling Code Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/01-Introduction.md Illustrates a code snippet that is expected to fail compilation. This is used to demonstrate error cases or unsupported operations. ```scala woozle(nel) // doesn't compile ``` -------------------------------- ### Add PostGIS JDBC Dependency Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Example of adding the PostGIS JDBC driver as a dependency in a Scala project. ```scala libraryDependencies += "net.postgis" % "postgis-jdbc" % "2.3.0" ``` -------------------------------- ### Run EXPLAIN on a PostgreSQL Query with doobie Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Use the `.explain` method on a doobie Query0 or Query to get query plan analysis. Requires `doobie.postgres._` and `doobie.postgres.implicits._` imports. Returns a `ConnectionIO[List[String]]`. ```scala import doobie.implicits._ import doobie.postgres.implicits._ sql"select name from country" .query[String] // Query0[String] .explain .transact(xa) .unsafeRunSync() .foreach(println) ``` -------------------------------- ### ResultSetIO Smart Constructor Example Source: https://github.com/typelevel/doobie/wiki/Low-Level-API Shows the ResultSetIO smart constructor corresponding to a Java ResultSet method. This is the primary interface for users not writing their own interpreters. ```java int findColumn(String columnLabel) // Java instance method ``` ```scala def findColumn(a: String): ResultSetIO[Int] ``` -------------------------------- ### Creating a Table with an Array Column Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/11-Arrays.md Define a SQL table with an array column using PostgreSQL syntax. This example includes dropping the table if it exists before creating it. ```scala val drop = sql"DROP TABLE IF EXISTS person".update.quick val create = sql""" CREATE TABLE person ( id SERIAL, name VARCHAR NOT NULL UNIQUE, pets VARCHAR[] NOT NULL ) """.update.quick ``` ```scala (drop *> create).unsafeRunSync() ``` -------------------------------- ### HikariCP Transactor Setup Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md Configure a HikariCP connection pool for use with Doobie's Transactor. Ensure HikariCP configurations are correctly set, and the transactor is managed as a Resource for clean shutdown. ```scala import cats.effect._ import cats.implicits._ import doobie._ import doobie.implicits._ import doobie.hikari._ import com.zaxxer.hikari.HikariConfig object HikariApp extends IOApp { // Resource yielding a transactor configured with a bounded connect EC and an unbounded // transaction EC. Everything will be closed and shut down cleanly after use. val transactor: Resource[IO, HikariTransactor[IO]] = for { hikariConfig <- Resource.pure { // For the full list of hikari configurations see https://github.com/brettwooldridge/HikariCP#gear-configuration-knobs-baby val config = new HikariConfig() config.setDriverClassName("org.h2.Driver") config.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1") config.setUsername("sa") config.setPassword("") config } xa <- HikariTransactor.fromHikariConfig[IO](hikariConfig) } yield xa def run(args: List[String]): IO[ExitCode] = transactor.use { xa => // Construct and run your server here! for { n <- sql"select 42".query[Int].unique.transact(xa) _ <- IO(println(n)) } yield ExitCode.Success } } ``` -------------------------------- ### DataSource Transactor Setup Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md Wrap an existing `javax.sql.DataSource` to create a Doobie Transactor. This requires providing an execution context for blocking operations. The `configure` method can be used for further customization. ```scala import javax.sql.DataSource // Resource yielding a DataSourceTransactor[IO] wrapping the given `DataSource` def transactor(ds: DataSource): Resource[IO, DataSourceTransactor[IO]] = for { ce <- ExecutionContexts.fixedThreadPool[IO](32) // our connect EC } yield Transactor.fromDataSource[IO](ds, ce) ``` -------------------------------- ### Connection Transactor Setup Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md Create a Doobie Transactor directly from an existing `java.sql.Connection`. You are responsible for managing the lifecycle (closing) of the provided `Connection`. An execution context for blocking operations must also be supplied. ```scala import java.sql.Connection // A Transactor[IO] wrapping the given `Connection` def transactor(c: Connection): Transactor[IO] = Transactor.fromConnection[IO](c, logHandler = None) ``` -------------------------------- ### Defining Data Structures and NonEmptyList Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/01-Introduction.md Example of defining a case class and creating a NonEmptyList. This is a common pattern for initializing collections with at least one element. ```scala case class Person(name: String, age: Int) val nel = NonEmptyList.of(Person("Bob", 12), Person("Alice", 14)) ``` -------------------------------- ### Define Geography Point Meta Manually Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Example of manually defining the Meta instance for a PostGIS geography Point type. ```scala // or define the implicit conversion manually implicit val geographyPoint: Meta[Point] = doobie.postgres.pgisgeographyimplicits.PointType ``` -------------------------------- ### Setting Parameters with HPS.set Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/05-Parameterized.md Shows different ways to use `HPS.set` to bind values to query parameters. Parameters are typically set starting from index 1. ```scala // Set parameters as (String, Boolean) starting at index 1 (default) HPS.set(("foo", true)) ``` ```scala // Set parameters as (String, Boolean) starting at index 1 (explicit) HPS.set(1, ("foo", true)) ``` ```scala // Set parameters individually HPS.set(1, "foo") *> HPS.set(2, true) ``` ```scala // Or out of order, who cares? HPS.set(2, true) *> HPS.set(1, "foo") ``` -------------------------------- ### Customize Query Execution with toAlteringExecution Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/19-Custom-JDBC-Operations.md Use `toAlteringExecution` to modify the execution steps of a query. This example customizes the `PreparedExecution` by setting a fetch size of 5. ```scala import cats.syntax.all._ import doobie.hi.connection.PreparedExecution fr"select name from country order by code limit 10" .query[String] .toAlteringExecution[List] { (steps: PreparedExecution[List[String]]) => steps.copy( process = FRS.setFetchSize(5) *> steps.process ) } .transact(xa) .unsafeRunSync() ``` -------------------------------- ### Running a doobie Program with a Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md Use the `transact` method on a doobie program to execute it using a provided Transactor. This method wraps the program with the Transactor's defined strategy for setup, error handling, and cleanup. ```scala program1.transact(xa) ``` -------------------------------- ### Handle Exceptions with onException and ensuring Source: https://github.com/typelevel/doobie/wiki/Error Handling Use `onException` to execute an action if an exception occurs, and `ensuring` to run a cleanup action regardless of success or failure. This example demonstrates transactional behavior with rollback on error and cleanup. ```scala (setAutoCommit(false) *> doStuff <* commit) onException rollback ensuring close ``` -------------------------------- ### DriverManager Transactor Setup Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/14-Managing-Connections.md Create a Doobie Transactor using JDBC's DriverManager. This is suitable for testing or simple applications where connection pooling is not required. Ensure the correct JDBC driver and URL are provided. ```scala import doobie.util.ExecutionContexts // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) ``` -------------------------------- ### Setting Parameters with FPS (Low-Level API) Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/05-Parameterized.md Demonstrates setting parameters using the low-level `doobie.free.FPS` constructors, which mirror the JDBC API and require specific methods for each parameter type. ```scala FPS.setString(1, "foo") *> FPS.setBoolean(2, true) ``` -------------------------------- ### Derive Get and Put for Scala 3 Enums Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Demonstrates deriving `Get` and `Put` instances for Scala 3 enums using `deriveEnumString`. The string values used for conversion are the literal names of the enum cases. ```scala enum Color: case Red, Green, Blue object Color: given Get[Color] = Get.deriveEnumString[Color] given Put[Color] = Put.deriveEnumString[Color] fr"SELECT 'Red'".query[Color].unique ``` -------------------------------- ### Define Get for PostgreSQL JSON Type Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Defines a `Get` instance for PostgreSQL's `json` type using JDBC's `OTHER` type and Circe's `Json`. It parses the `PGobject` value, returning parse errors as strings. ```scala implicit val showPGobject: Show[PGobject] = Show.show(_.getValue.take(250)) implicit val jsonGet: Get[Json] = Get.Advanced.other[PGobject](NonEmptyList.of("json")).temap[Json] { o => parse(o.getValue).leftMap(_.show) } ``` -------------------------------- ### Quickly Execute and Print Query Results Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/04-Selecting.md Use the '.quick' method to execute a Query0 or Stream and print the results to the console. This is intended for REPL exploration. ```scala sql"select name from country" .query[String] // Query0[String] .stream // Stream[ConnectionIO, String] .take(5) // Stream[ConnectionIO, String] .quick // IO[Unit] .unsafeRunSync() ``` -------------------------------- ### Define a Simple ConnectionIO Program Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/03-Connecting.md Create a basic doobie program that returns a constant value within the ConnectionIO context. ```scala val program1 = 42.pure[ConnectionIO] ``` -------------------------------- ### Query PostgreSQL Enum as Scala Enumeration Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Example of querying a PostgreSQL enum type mapped to a Scala Enumeration. ```scala sql"select 'foo'::myenum".query[MyEnum.Value].unique.transact(xa).unsafeRunSync() ``` -------------------------------- ### Create Query0 from arbitrary SQL string Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/17-FAQ.md Shows how to construct a `Query0` from an arbitrary SQL string, including dynamic ordering based on a boolean flag. ```scala case class Code(country: String) case class City(code: Code, name: String, population: Int) def cities(code: Code, asc: Boolean): Query0[City] = { val ord = if (asc) fr"ASC" else fr"DESC" val sql = fr""" SELECT countrycode, name, population FROM city WHERE countrycode = $code ORDER BY name""" ++ ord sql.query[City] } ``` -------------------------------- ### Accessing Raw JDBC ResultSet Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/19-Custom-JDBC-Operations.md Use `FRS.raw` to get direct access to the underlying `java.sql.ResultSet` object for custom operations. ```scala import doobie.FRS // alias for doobie.free.resultset FRS.raw { resultSet: java.sql.ResultSet => // ... do something with the ResultSet resultSet.getInt(1) } ``` -------------------------------- ### Summoning Write Instances Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/05-Parameterized.md Demonstrates how to summon `Write` instances for different types, which are required for setting parameters in the high-level API. ```scala Write[(String, Boolean)] ``` ```scala Write[Country] ``` -------------------------------- ### Query PostgreSQL Enum as Custom Scala Type Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Example of querying a PostgreSQL enum type mapped to a custom Scala type. ```scala sql"select 'foo'::myenum".query[FooBar].unique.transact(xa).unsafeRunSync() ``` -------------------------------- ### Setting up a Doobie Transactor and YOLO Mode Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/05-Parameterized.md This code sets up a `Transactor` for database connections using `DriverManager` and enables YOLO mode for easier testing. It includes necessary imports and configuration for a PostgreSQL database. ```scala import doobie._ import doobie.implicits._ import doobie.util.ExecutionContexts import cats._ import cats.data._ import cats.effect._ import cats.implicits._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) val y = xa.yolo import y._ ``` ```scala implicit val mdocColors: doobie.util.Colors = doobie.util.Colors.None ``` -------------------------------- ### Setting up a Doobie Transactor for Testing Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/13-Unit-Testing.md Configure a Transactor for testing with specified JDBC driver, URL, user, and password. Logging is disabled by default for simplicity. ```scala import doobie._ import doobie.implicits._ import cats._ import cats.data._ import cats.effect._ import cats.implicits._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) ``` -------------------------------- ### Passing Context to LogHandler with IOLocal Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/10-Logging.md Example of using cats-effect's IOLocal to pass contextual information, such as the current user, to a custom LogHandler. ```scala import cats.effect.{IOLocal, Ref} import doobie.util.log.Success def users = List.range(0, 4).map(n => s"user-$n") def program: IO[List[String]] = for { // define an IOLocal where we store the user which caused the query to be run currentUser <- IOLocal("") // store all successful sql here, for all users successLogsRef <- Ref[IO].of(List.empty[String]) xa = Transactor.fromDriverManager[IO]( driver = "org.h2.Driver", url = "jdbc:h2:mem:queryspec;DB_CLOSE_DELAY=-1", user = "sa", password = "", logHandler = Some(new LogHandler[IO] { def run(logEvent: LogEvent): IO[Unit] = currentUser.get.flatMap(user => successLogsRef.update(logs => s"sql for user $user: '${logEvent.sql}'" :: logs)) }) ) // run a bunch of queries _ <- users.parTraverse(user => for { _ <- currentUser.set(user) _ <- sql"select 1".query[Int].unique.transact(xa) } yield () ) // return collected log messages logs <- successLogsRef.get } yield logs program.unsafeRunSync().sorted ``` -------------------------------- ### Configuring a Doobie Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/19-Custom-JDBC-Operations.md Set up a `Transactor` for `IO` using `Transactor.fromDriverManager` to connect to a database. ```scala import cats.effect.IO import cats.effect.unsafe.implicits.global // To allow .unsafeRunSync import doobie.Transactor // Create the transactor val xa: Transactor[IO] = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", url = "jdbc:postgresql:world", user = "postgres", password = "password", logHandler = None ) ``` -------------------------------- ### Execute a ConnectionIO Program Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/03-Connecting.md Transact a ConnectionIO program using the configured Transactor and run the resulting IO action to completion. ```scala val io = program1.transact(xa) io.unsafeRunSync() ``` -------------------------------- ### Set Doobie Version for Documentation Publishing Source: https://github.com/typelevel/doobie/blob/main/CONTRIBUTING.md Before publishing documentation, set the project version to a 'nice' tag. This can be done by checking out the release tag or explicitly setting the version in sbt. ```bash sbtn 'set ThisBuild / version := "" ' ``` -------------------------------- ### Execute Query with Different Filter Combinations Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/08-Fragments.md Demonstrates executing the `select` query with varying filter conditions: no filters, one filter, and three filters. ```scala select(None, None, Nil, 10).check.unsafeRunSync() // no filters ``` ```scala select(Some("U%"), None, Nil, 10).check.unsafeRunSync() // one filter ``` ```scala select(Some("U%"), Some(12345), List("FRA", "GBR"), 10).check.unsafeRunSync() // three filters ``` -------------------------------- ### Setting Up doobie Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/09-Error-Handling.md This code sets up a doobie Transactor for PostgreSQL, configuring connection details and disabling logging. It also imports necessary implicits for YOLO-style execution. ```scala import doobie._ import doobie.implicits._ import doobie.util.ExecutionContexts import cats._ import cats.data._ import cats.effect._ import cats.implicits._ // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL - Driver specific user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) val y = xa.yolo import y._ ``` ```scala implicit val mdocColors: doobie.util.Colors = doobie.util.Colors.None ``` -------------------------------- ### Transact a Stream for Direct Streaming Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/04-Selecting.md Transact a Stream[ConnectionIO, A] directly to obtain a Stream[IO, A]. This allows for direct streaming of results, for example, to an HTTP response. ```scala val p: Stream[IO, Country2] = { sql"select name, population, gnp from country" .query[Country2] // Query0[Country2] .stream // Stream[ConnectionIO, Country2] .transact(xa) // Stream[IO, Country2] } p.take(5).compile.toVector.unsafeRunSync().foreach(println) ``` -------------------------------- ### Select Multiple Columns into a Tuple Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/04-Selecting.md Map multiple columns to a tuple, including nullable types as Options. This example selects code, name, population, and gnp. ```scala sql"select code, name, population, gnp from country" .query[(String, String, Int, Option[Double])] .stream .take(5) .quick .unsafeRunSync() ``` -------------------------------- ### Run ConnectionIO program with Task Source: https://github.com/typelevel/doobie/wiki/The-Big-Picture Transkoms a `ConnectionIO` program to a `Task` monad, preparing it for execution. This demonstrates converting a Doobie-specific effect type to a more general-purpose one. ```scala queryByAge(10).transK[Task] // Kleisli[Task, Connection, List[Person]] ``` -------------------------------- ### Enable YOLO Mode for REPL Exploration Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/04-Selecting.md Import the 'yolo' syntax from your Transactor for simplified query execution in the REPL. A stable reference to the Transactor is required. ```scala val y = xa.yolo // a stable reference is required import y._ ``` -------------------------------- ### Custom Meta for scala.xml.Elem and SQLXML Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/17-FAQ.md Provides a custom Meta instance to map scala.xml.Elem to SQLXML via streaming. This is useful when Doobie does not have a predefined strategy for SQLXML. ```scala import doobie.enumerated.JdbcType.Other import java.sql.SQLXML import scala.xml.{ XML, Elem } implicit val XmlMeta: Meta[Elem] = Meta.Advanced.one[Elem]( Other, NonEmptyList.of("xml"), (rs, n) => XML.load(rs.getObject(n).asInstanceOf[SQLXML].getBinaryStream), (ps, n, e) => { val sqlXml = ps.getConnection.createSQLXML val osw = new java.io.OutputStreamWriter(sqlXml.setBinaryStream) XML.write(osw, e, "UTF-8", false, null) osw.close ps.setObject(n, sqlXml) }, (_, _, _) => sys.error("update not supported, sorry") ) ``` -------------------------------- ### Example of Unmapped Type Error (Statement Parameter) Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Demonstrates a type error that occurs when attempting to use an unmapped type (`String` and `Exception`) as a statement parameter in doobie. ```scala def nope(msg: String, ex: Exception): ConnectionIO[Int] = sql"INSERT INTO log (message, detail) VALUES ($msg, $ex)".update.run ``` -------------------------------- ### Running a Doobie Program Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/19-Custom-JDBC-Operations.md Execute a `ConnectionIO` program using the configured `Transactor` with `.transact(xa).unsafeRunSync()`. ```scala program.transact(xa).unsafeRunSync() ``` -------------------------------- ### Querying Array of Enums Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/11-Arrays.md Use the defined `Meta` instance to query columns that are arrays of enums. This example demonstrates querying a PostgreSQL array literal into a `List[MyEnum]`. ```scala sql"select array['foo', 'bar'] :: myenum[]".query[List[MyEnum]].quick.unsafeRunSync() ``` -------------------------------- ### Interpret ConnectionIO to Kleisli Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/03-Connecting.md Demonstrates interpreting a `ConnectionIO` program into a `Kleisli[IO, Connection, A]` using `KleisliInterpreter`. This allows running doobie programs in a target monad like `IO`. ```scala import cats.~> import cats.data.Kleisli import doobie.free.connection.ConnectionOp import java.sql.Connection val interpreter = KleisliInterpreter[IO](LogHandler.noop).ConnectionInterpreter val kleisli = program1.foldMap(interpreter) val io3 = IO(null: java.sql.Connection) >>= kleisli.run io3.unsafeRunSync() // sneaky; program1 never looks at the connection ``` -------------------------------- ### Configure a DriverManager Transactor Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/03-Connecting.md Set up a Transactor using DriverManager to obtain database connections. This is suitable for development. ```scala import doobie.util.ExecutionContexts // This is just for testing. Consider using cats.effect.IOApp instead of calling // unsafe methods directly. import cats.effect.unsafe.implicits.global // A transactor that gets connections from java.sql.DriverManager and executes blocking operations // on an our synchronous EC. See the chapter on connection handling for more info. val xa = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", // JDBC driver classname url = "jdbc:postgresql:world", // Connect URL user = "postgres", // Database user name password = "password", // Database password logHandler = None // Don't setup logging for now. See Logging page for how to log events in detail ) ``` -------------------------------- ### Example of Unmapped Type Error (Query Result) Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Illustrates a type error encountered when trying to query rows into a data type (`LogEntry`) that includes an unmapped member type (`Exception`). ```scala sql"SELECT message, detail FROM log".query[LogEntry] ``` -------------------------------- ### Define a query with explicit lifting Source: https://github.com/typelevel/doobie/wiki/The-Big-Picture Defines a `ConnectionIO` program to query `Person` records by age using explicit lifting of `PreparedStatementIO` and `ResultSetIO`. This approach ensures resource safety through Doobie's combinators. ```scala val readPeople: ResultSetIO[List[Person]] = readPerson.whileM[List](HRS.next) def queryByAge(n: Int): ConnectionIO[List[Person]] = HC.prepareStatement("SELECT FIRST, LAST, AGE FROM PERSON WHERE AGE = ?") { for { _ <- HPS.set(n) ps <- HPS.executeQuery(readPeople) } yield ps // equivalently, set(n) *> executeQuery(readPeople) } ``` -------------------------------- ### Define Nat Type and Conversions Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Defines a `Nat` (natural number) type with `Zero` and `Succ` constructors, along with functions to convert between `Nat` and `Int`. This setup is necessary for creating custom mappings. ```scala object NatModule { sealed trait Nat case object Zero extends Nat case class Succ(n: Nat) extends Nat def toInt(n: Nat): Int = { def go(n: Nat, acc: Int): Int = n match { case Zero => acc case Succ(n) => go(n, acc + 1) } go(n, 0) } def fromInt(n: Int): Nat = { def go(n: Int, acc: Nat): Nat = if (n <= 0) acc else go(n - 1, Succ(acc)) go(n, Zero) } } import NatModule._ ``` -------------------------------- ### Run Doobie program with DriverManager Source: https://github.com/typelevel/doobie/wiki/The-Big-Picture Executes a `ConnectionIO` program directly using `DriverManager`. The program is first lifted to a `Task` and then run, yielding the result or throwing an exception. ```scala val prog = HDM.getConnection("jdbc:whatevs:stuff:etc", "user", "pass")(queryByAge(42)) val task = prog.trans[Task] // Task[List[Person]] val people = task.run // List[Person], side-effecting, may throw ``` -------------------------------- ### Configure and use DriverManagerTransactor Source: https://github.com/typelevel/doobie/wiki/The-Big-Picture Sets up a `DriverManagerTransactor` for `Task` and uses it to execute a `ConnectionIO` program. This abstracts over connection management, allowing for different backends like JNDI or connection pools. ```scala val xa = DriverManagerTransactor[Task]("my.driver.class", "jdbc:whatevs:stuff:etc", "user", "pass") val task = xa.transact(queryByAge(42)) // Task[List[Person]] ``` -------------------------------- ### Define Meta for PostgreSQL JSON Type Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Combines `Get` and `Put` operations for PostgreSQL's `json` type into a single `Meta` instance. It uses `Meta.Advanced.other` and handles potential parsing errors by throwing them. ```scala implicit val jsonMeta: Meta[Json] = Meta.Advanced.other[PGobject]("json").timap[Json]( a => parse(a.getValue).leftMap[Json](e => throw e).merge)( a => { val o = new PGobject o.setType("json") o.setValue(a.noSpaces) o } ) ``` -------------------------------- ### Creating a Table Schema Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/04-Selecting.md SQL DDL to create the 'country' table. This is for reference and not executable doobie code. ```sql CREATE TABLE country ( code character(3) NOT NULL, name text NOT NULL, population integer NOT NULL, gnp numeric(10,2) -- more columns, but we won't use them here ) ``` -------------------------------- ### Syntactic Sugar for Update Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/07-Updating.md Demonstrates how `sql"... $a $b ...".update` is syntactic sugar for `Update[(Int, String)]("... ? ? ...").run((a, b))`. ```scala // Given some values ... val a = 1; val b = "foo" // this expression ... sql"... $a $b ..." // is syntactic sugar for this one, which is an Update applied to (a, b) Update[(Int, String)]("... ? ? ...").run((a, b)) ``` -------------------------------- ### Derive Meta for Nat using .imap Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Defines a `Meta` instance for `Nat` by mapping from `Meta[Int]`. The `Meta` typeclass combines `Get` and `Put` instances, providing a convenient way to define bidirectional mappings. ```scala // Bidirectional schema mapping for Nat, in terms of Int implicit val natMeta: Meta[Nat] = Meta[Int].imap(fromInt)(toInt) ``` -------------------------------- ### MUnit Integration for Doobie Query Testing Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/13-Unit-Testing.md Use `doobie.munit.IOChecker` with MUnit's `FunSuite` for testing doobie queries. Ensure the `Transactor` is correctly configured. ```scala import _root_.munit._ class AnalysisTestSuite extends FunSuite with doobie.munit.IOChecker { override val colors = doobie.util.Colors.None // just for docs val transactor = Transactor.fromDriverManager[IO]( driver = "org.postgresql.Driver", url = "jdbc:postgresql:world", user = "postgres", password = "password", logHandler = None ) test("trivial") { check(trivial) } test("biggerThan") { checkOutput(biggerThan(0)) } test("update") { check(update) } } ``` -------------------------------- ### Executing a Transacted Query Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/index.md Demonstrates how to execute a previously defined query using the transactor and obtain the result. ```scala find("France").transact(xa).unsafeRunSync() ``` -------------------------------- ### Insert Rows into Person Table Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/07-Updating.md Inserts rows into the 'person' table using the defined `insert1` method. The first insert uses `.run` to get the row count, while the second uses `.quick` in YOLO mode for immediate execution and output. ```scala insert1("Alice", Some(12)).run.transact(xa).unsafeRunSync() insert1("Bob", None).quick.unsafeRunSync() // switch to YOLO mode ``` -------------------------------- ### Custom Meta for Postgres Domains with Check Constraints Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/17-FAQ.md Defines a helper function 'string' to create a Meta instance for Postgres domains with check constraints, which otherwise type check as DISTINCT. This allows for proper type checking by mapping to JdbcType.Distinct and JdbcType.VarChar. ```scala import cats.data.NonEmptyList import doobie._ import doobie.enumerated.JdbcType object distinct { def string(name: String): Meta[String] = Meta.Advanced.many( NonEmptyList.of(JdbcType.Distinct, JdbcType.VarChar), NonEmptyList.of(name), _ getString _, _.setString(_, _), _.updateString(_, _) ) } case class NonEmptyString(value: String) // If the domain for NonEmptyStrings is nes implicit val nesMeta: Meta[NonEmptyString] = { distinct.string("nes").imap(NonEmptyString.apply)(_.value) } ``` -------------------------------- ### Deriving Read and Write for Custom Types Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md Define custom Read and Write instances for types not eligible for automatic derivation by mapping them to a type with existing instances. This example shows how to map a Java AWT Point to a Scala tuple of Ints. ```scala implicit val pointRead: Read[Point] = Read[(Int, Int)].map { case (x, y) => new Point(x, y) } ``` ```scala implicit val pointWrite: Write[Point] = Write[(Int, Int)].contramap(p => (p.x, p.y)) ``` -------------------------------- ### Batch Insert Data using COPY FROM STDIN Source: https://github.com/typelevel/doobie/blob/main/modules/docs/src/main/mdoc/docs/15-Extensions-PostgreSQL.md Provides a generic function `insert` to perform batch inserts into the 'food' table using the `COPY ... FROM STDIN` command. It accepts any `Foldable` collection of `Food` objects. ```scala def insert[F[_]: Foldable](fa: F[Food]): ConnectionIO[Long] = sql"COPY food (name, vegetarian, calories) FROM STDIN".copyIn(fa) ```