skunk
'''Skunk''' is a functional data access layer for Postgres.
Design principles:
- Skunk doesn't use JDBC. It speaks the Postgres wire protocol. It will not work with any other database back end.
- Skunk is asynchronous all the way down, via cats-effect, fs2, and ultimately nio. The
high-level network layers (
Protocol
andSession
) are safe to use concurrently. - Serialization to and from schema types is not typeclass-based, so there are no implicit derivations. Codecs are explicit, like parser combinators.
- I'm not sweating arity abstraction that much. Pass
a ~ b ~ c
for three args andVoid
if there are no args. This may change in the future but it's fine for now. - Skunk uses
Resource
for lifetime-managed objects, which means it takes some discipline to avoid leaks, especially when working concurrently. May or may not end up being problematic. - I'm trying to write good Scaladoc this time.
A minimal example follows. We construct a Resource
that yields a Session
, then use it.
package example
import cats.effect._
import skunk._
import skunk.implicits._
import skunk.codec.numeric._
object Minimal extends IOApp {
val session: Resource[IO, Session[IO]] =
Session.single(
host = "localhost",
port = 5432,
user = "postgres",
database = "world",
)
def run(args: List[String]): IO[ExitCode] =
session.use { s =>
for {
n <- s.unique(sql"select 42".query(int4))
_ <- IO(println(s"The answer is $n."))
} yield ExitCode.Success
}
}
Continue reading for an overview of the library. It's pretty small.
Attributes
Members list
Queries and Commands
Skunk recognizes two classes of statements: Query
, for statements
that return rows; and Command
, for statements that do not return rows. These values can be
constructed directly but typically arise via the sql
interpolator.
val q = sql"""
SELECT id, name
FROM employee
WHERE age > $int2
""".query(int4 ~ varchar) // Query[Short, Long ~ String]
In the above example note that query parameters are specified by interpolated Encoder
s and
column types are specified by a Decoder
passed to .query
. The ~
syntax constructs
left-associated HLists of types and values via nested pairs. These are all described in more
detail a bit further down.
Commands are constructed in a similar way but have no output columns and thus no Decoder
is
needed.
val c = sql"""
UPDATE employee
SET salary = salary * 1.05
WHERE id = $int8
""".command // Command[Long]
The interpolator also permits nested Fragment
s and interpolated constants like table names.
See StringContextOps
for more information on the interpolator.
SQL and parameter encoder for a statement that returns no rows. We assume that sql
has the
same number of placeholders of the form $1
, $2
, etc., as the number of slots encoded by
encoder
, and that the parameter types specified by encoder
are consistent with the schema.
The check
methods on Session provide a means to verify this assumption.
SQL and parameter encoder for a statement that returns no rows. We assume that sql
has the
same number of placeholders of the form $1
, $2
, etc., as the number of slots encoded by
encoder
, and that the parameter types specified by encoder
are consistent with the schema.
The check
methods on Session provide a means to verify this assumption.
You can construct a Command
directly, although it is more typical to use the sql
interpolator.
sql"INSERT INTO foo VALUES ($int2, $varchar)".command // Command[(Short, String)]
Attributes
- encoder
An encoder for all parameters
$1
,$2
, etc., insql
.- sql
A SQL statement returning no rows.
- See also:
StringContextOps for information on the
sql
interpolator.Session for information on executing a
Command
.- Companion:
- object
- Source:
- Command.scala
- Graph
- Supertypes
A composable, embeddable hunk of SQL and typed parameters (common precursor to Command
and
Query
). Although it is possible to construct a Fragment
directly it is more typical to use
the sql
interpolator.
A composable, embeddable hunk of SQL and typed parameters (common precursor to Command
and
Query
). Although it is possible to construct a Fragment
directly it is more typical to use
the sql
interpolator.
Attributes
- Companion:
- object
- Source:
- Fragment.scala
- Graph
- Supertypes
SQL, parameter encoder, and row decoder for a statement that returns rows. We assume that sql
has the same number of placeholders of the form $1
, $2
, etc., as the number of slots encoded
by encoder
, that sql
selects the same number of columns are the number of slots decoded by
decoder
, and that the parameter and column types specified by encoder
and decoder
are
consistent with the schema. The check
methods on Session provide a means to
verify this assumption.
SQL, parameter encoder, and row decoder for a statement that returns rows. We assume that sql
has the same number of placeholders of the form $1
, $2
, etc., as the number of slots encoded
by encoder
, that sql
selects the same number of columns are the number of slots decoded by
decoder
, and that the parameter and column types specified by encoder
and decoder
are
consistent with the schema. The check
methods on Session provide a means to
verify this assumption.
You can construct a Query
directly, although it is more typical to use the sql
interpolator.
sql"SELECT name, age FROM person WHERE age > $int2".query(varchar *: int2) // Query[Short, (String, Short)]
Attributes
- decoder
A decoder for selected columns.
- encoder
An encoder for all parameters
$1
,$2
, etc., insql
.- origin
The
Origin
where the sql was defined, if any.- sql
A SQL statement returning no rows.
- See also:
StringContextOps for information on the
sql
interpolator.Session for information on executing a
Query
.- Companion:
- object
- Source:
- Query.scala
- Graph
- Supertypes
Session Values
Skunk's central abstraction is the Session
, which represents a connection
to Postgres. From the Session
we can produce prepared statements, cursors, and other
resources that ultimately depend on their originating Session
.
A '''channel''' that can be used for inter-process communication, implemented in terms of
LISTEN
and NOTIFY
. All instances start life as a Channel[F, String, Notification]
but can
be mapped out to different input and output types. See the linked documentation for more
information on the transactional semantics of these operations.
A '''channel''' that can be used for inter-process communication, implemented in terms of
LISTEN
and NOTIFY
. All instances start life as a Channel[F, String, Notification]
but can
be mapped out to different input and output types. See the linked documentation for more
information on the transactional semantics of these operations.
Attributes
- See also:
- Companion:
- object
- Source:
- Channel.scala
- Graph
- Supertypes
- Self type
An open cursor from which rows can be fetched, valid during the lifetime its defining Session
.
You can use this mechanism to implement chunked reads and paged results, although it is ofen
more pleasant to use a Cursor
-backed Stream
, as produced by PreparedQuery#stream.
An open cursor from which rows can be fetched, valid during the lifetime its defining Session
.
You can use this mechanism to implement chunked reads and paged results, although it is ofen
more pleasant to use a Cursor
-backed Stream
, as produced by PreparedQuery#stream.
Attributes
- Companion:
- object
- Source:
- Cursor.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
A prepared command, valid for the life of its defining Session
.
A prepared command, valid for the life of its defining Session
.
Attributes
- Companion:
- object
- Source:
- PreparedCommand.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
A prepared query, valid for the life of its originating Session
.
A prepared query, valid for the life of its originating Session
.
Attributes
- Companion:
- object
- Source:
- PreparedQuery.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
Represents a live connection to a Postgres database. Operations provided here are safe to use
concurrently. Note that this is a lifetime-managed resource and as such is invalid outside the
scope of its owning Resource
, as are any streams constructed here. If you start
an operation
be sure to join
its Fiber
before releasing the resource.
Represents a live connection to a Postgres database. Operations provided here are safe to use
concurrently. Note that this is a lifetime-managed resource and as such is invalid outside the
scope of its owning Resource
, as are any streams constructed here. If you start
an operation
be sure to join
its Fiber
before releasing the resource.
See the companion object for information on obtaining a pooled or single-use instance.
Attributes
- Companion:
- object
- Source:
- Session.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Known subtypes
- class Impl[F]
Codecs
When you construct a statement each parameter is specified via an Encoder
, and
row data is specified via a Decoder
. In some cases encoders and decoders are symmetric and
are defined together, as a Codec
. There are many variants of this pattern in functional
Scala libraries; this is closest in spirit to the strategy adopted by scodec.
Symmetric encoder and decoder of Postgres text-format data to and from Scala types.
Symmetric encoder and decoder of Postgres text-format data to and from Scala types.
Attributes
- Companion:
- object
- Source:
- Codec.scala
- Graph
- Supertypes
- Self type
- Codec[A]
Decoder of Postgres text-format data into Scala types.
Decoder of Postgres text-format data into Scala types.
Attributes
- Companion:
- object
- Source:
- Decoder.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Known subtypes
- trait Codec[A]
- Self type
- Decoder[A]
Encoder of Postgres text-format data from Scala types.
Encoder of Postgres text-format data from Scala types.
Attributes
- Companion:
- object
- Source:
- Encoder.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Known subtypes
- trait Codec[A]
- Self type
- Encoder[A]
A singly-inhabited type representing arguments to a parameterless statement.
A singly-inhabited type representing arguments to a parameterless statement.
Attributes
- Companion:
- object
- Source:
- Void.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Known subtypes
- object Void.type
HLists
This idea was borrowed from scodec. We use ~
to build left-associated nested
pairs of values and types, and can destructure with ~
the same way.
val a: Int ~ String ~ Boolean =
1 ~ "foo" ~ true
a match {
case n ~ s ~ b => ...
}
Note that the ~
operation for Codec
, Encoder
, and Decoder
is lifted. This is usually
what you want. If you do need an HList of encoders you can use Tuple2
.
val c: Encoder[Int ~ String ~ Boolean]
int4 ~ bpchar ~ bit
// Unusual, but for completeness you can do it thus:
val d: Encoder[Int] ~ Encoder[String] ~ Encoder[Boolean] =
((int4, bpchar), bit)
It is possible that we will end up switching to shapeless.HList
but this is good for now.
Companion providing unapply for ~
such that (x ~ y ~ z) match { case a ~ b ~ c => ... }
.
Companion providing unapply for ~
such that (x ~ y ~ z) match { case a ~ b ~ c => ... }
.
Attributes
- Source:
- package.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- ~.type
Infix alias for (A, B)
that provides convenient syntax for left-associated HLists.
Infix alias for (A, B)
that provides convenient syntax for left-associated HLists.
Attributes
- Source:
- package.scala
Companion Objects
Companion objects for the traits and classes above.
Attributes
- Companion:
- trait
- Source:
- Channel.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- Channel.type
Attributes
- Companion:
- trait
- Source:
- Codec.scala
- Graph
- Supertypes
- Self type
- Codec.type
Attributes
- Companion:
- class
- Source:
- Command.scala
- Graph
- Supertypes
- trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
- Command.type
Attributes
- Companion:
- trait
- Source:
- Cursor.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- Cursor.type
Attributes
- Companion:
- trait
- Source:
- Decoder.scala
- Graph
- Supertypes
- Self type
- Decoder.type
Attributes
- Companion:
- trait
- Source:
- Encoder.scala
- Graph
- Supertypes
- Self type
- Encoder.type
Attributes
- Companion:
- class
- Source:
- Fragment.scala
- Graph
- Supertypes
- Self type
- Fragment.type
Attributes
- Companion:
- trait
- Source:
- PreparedCommand.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- PreparedCommand.type
Attributes
- Companion:
- trait
- Source:
- PreparedQuery.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- PreparedQuery.type
Attributes
- Companion:
- class
- Source:
- Query.scala
- Graph
- Supertypes
- trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
- Query.type
Attributes
- Companion:
- trait
- Source:
- Session.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- Session.type
Type members
Classlikes
A fragment applied to its argument, yielding an existentially-typed fragment + argument pair that can be useful when constructing dynamic queries in application code. Applied fragments must be deconstructed in order to prepare and execute.
A fragment applied to its argument, yielding an existentially-typed fragment + argument pair that can be useful when constructing dynamic queries in application code. Applied fragments must be deconstructed in order to prepare and execute.
Attributes
- Companion:
- object
- Source:
- AppliedFragment.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
Attributes
- Companion:
- trait
- Source:
- AppliedFragment.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- AppliedFragment.type
Enumerated type of Postgres error codes. These can be used as extractors for error handling, for example:
Enumerated type of Postgres error codes. These can be used as extractors for error handling, for example:
doSomething.recoverWith { case SqlState.ForeignKeyViolation(ex) => ... }
Attributes
- See also:
- Source:
- SqlState.scala
- Graph
- Supertypes
Attributes
- Companion:
- object
- Source:
- Statement.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Known subtypes
Attributes
- Companion:
- trait
- Source:
- Statement.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- Statement.type
Control methods for use within a transaction
block. An instance is provided when you call
Session.transaction(...).use
.
Control methods for use within a transaction
block. An instance is provided when you call
Session.transaction(...).use
.
Attributes
- See also:
Session#transaction for information on default commit/rollback behavior
- Companion:
- object
- Source:
- Transaction.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- Transaction[F]
Attributes
- Companion:
- trait
- Source:
- Transaction.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- Transaction.type
Attributes
- Source:
- feature.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- feature.type
Attributes
- Source:
- feature.scala
- Graph
- Supertypes
- class Objecttrait Matchableclass Any
- Self type
- featureFlags.type
Attributes
- Source:
- package.scala
- Graph
- Supertypes
- trait ToAllOpstrait ToDecoderOpstrait ToDecoderOpsLowtrait ToEncoderOpstrait ToEncoderOpsLowtrait ToCodecOpstrait ToCodecOpsLowtrait ToListOpstrait ToStringContextOpstrait ToIdOpsclass Objecttrait Matchableclass Any
- Self type
- implicits.type
Value members
Concrete fields
Attributes
- Source:
- package.scala