0.9.0.0
Version 0.9.0.0
Thanks to William Yao and Cullin Poresky for their contributions!
Prepared Statements
Squeal 0.9 adds a new Prepared
type for prepared statements.
data Prepared m x y = Prepared
{ runPrepared :: x -> m y -- ^ execute a prepared statement
, deallocate :: m () -- ^ manually clean up a prepared statement
}
This allows to factor and generalize the functions executePrepared
and executePrepared_
. Squeal 0.9 adds new methods prepare
and
prepare_
to the MonadPQ
typeclass.
prepare
:: MonadPQ pq
=> Statement db x y
-> pq (Prepared pq x (Result y))
prepare_
:: MonadPQ pq
=> Statement db x ()
-> pq (Prepared pq x ())
They may then be run using runPrepared
and manually cleaned up
using deallocate
. The Prepared
type has a cornucopia of instances
allowing you to combine prepared statements in lots of ways. Instances
Prepared
supports include Category
, Arrow
, Profunctor
and more.
A function preparedFor
abstracts the pattern of preparing a statement,
then doing something with it and finally deallocating. That something
can be thought of as an "optic", a generalization of lenses.
preparedFor
:: MonadPQ db pq
=> (Prepared pq a (Result b) -> Prepared pq s t)
-- ^ transform the input and output using an "optic"
-> Statement db a b -- ^ query or manipulation
-> s -> pq t
For instance, using the optic traverse'
recovers the function
executePrepared
and using the optic wander traverse_
recovers the
function executePrepared_
, which are used for running prepared statements
over Traversable
or Foldable
containers of parameters respectively.
With the generalized notion of a Prepared
object, you can prepare statments
and optionally combine them at the beginning of a database session and
have a Prepared
object to use with runPrepared
throughout the session.
This is a lower level primitive and closer to the model that PostgreSQL
actually provides than what Squeal previously allowed.
Row and Enum Types
Squeal 0.9 adds a number of new features for row and enum types.
First, new type families DbRelations
and DbEnums
have been added,
which filter a SchemasType
down to all row or enum types.
A relation means a table, view or composite type;
other kinds of relations are not currently supported. Previously,
Squeal's support for row types only covered composite types but
Squeal 0.9 adds more support for tables and views. New TypeExpression
s
typerow
and typeenum
have been added. A new type family FindQualified
,
which looks through database schemas to find a row or enum type has been added.
Squeal will now look through all tables, views and composite types when
trying to find a user-defined relation to match your row type where previously
it had only looked for composites.
Next, new functions have been added to allow users to define manual encodings
for row and enum types. Previously, Squeal only had functions to allow users to
define manual decodings for row and enum types. For enum types,
you can now use enumParam
like so:
data Dir = North | South | East | West
instance IsPG Dir where
type PG Dir = 'PGenum '["north", "south", "east", "west"]
instance ToPG db Dir where
toPG = enumParam $ \case
North -> label @"north"
South -> label @"south"
East -> label @"east"
West -> label @"west"
For row types you can now use rowParam
together with new combinators
.#
to cons and #.
to end the row like so:
data Quaternion = Quaternion
{ real :: Double
, imaginaryI :: Double
, imaginaryJ :: Double
, imaginaryK :: Double
}
instance IsPG Quaternion where
type PG Quaternion = 'PGcomposite '[
"re" ::: 'NotNull 'PGfloat8,
"im" ::: 'NotNull 'PGfloat8,
"jim" ::: 'NotNull 'PGfloat8,
"kim" ::: 'NotNull 'PGfloat8]
instance ToPG db Quaternion where
toPG = rowParam $
real `as` #re
.# imaginaryI `as` #im
.# imaginaryJ `as` #jim
#. imaginaryK `as` #kim
There is also a function genericRowParams
, which can
be used with combinators like so:
data L = L {frst :: Int16, scnd :: Char}
deriving stock (GHC.Generic, Show)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
data R = R {thrd :: Bool, frth :: Bool}
deriving stock (GHC.Generic, Show)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
instance IsPG (L,R) where
type PG (L,R) = 'PGcomposite '[
"frst" ::: 'NotNull 'PGint2,
"scnd" ::: 'NotNull ('PGchar 1),
"thrd" ::: 'NotNull 'PGbool,
"frth" ::: 'NotNull 'PGbool]
instance ToPG db (L,R) where
toPG = rowParam $
contramap fst genericRowParams
`appendParams`
contramap snd genericRowParams
All of this is made possible by generalizing the EncodeParams
type to polykinded:
newtype EncodeParams
(db :: SchemasType)
(tys :: [k])
(x :: Type)
Since it is polykinded, the tys
parameter can have either
the kind [NullType]
or the kind RowType
.
Other Changes
Squeal 0.9 adds support for GHC 9, which required fully saturating
a number of functions that involved RankNTypes
, a change
required by the "simplified subsumption" proposal.
A bug for Has
custom type errors, which made it expensive
in the case of a lookup failure because of use of the strict If
type family, has been fixed, thanks to Cullin.
Missing images and some small fixes were added for the Squeal
"Core Concepts Handbook", thanks to William.
CI has been fixed to properly test across different versions of GHC.
The function notNull
which has a non-intuitive name has been
deprecated and a replacement function just_
has been added. The
terms null_
and just_
now intentionally connote Nothing
and
Just
from Haskell's Maybe
type.
The operators (.<@)
and (@>.)
as well as the functions arrAny
and arrAll
have been generalized to allow Null
arguments. Previously,
they had been improperly restricted to have NotNull
arguments.
PQ
has been given MonadFix
, Alternative
and MonadPlus
instances.