@@ -0,0 +1,1217 @@
5+Version 0.5 makes a number of large changes and additions to Squeal.
6+I want to thank folks who contributed issues and pull requests;
7+Raveline, rimmington, ilyakooo0, chshersh, reygoch, and more.
9+**Multi-schema support**
11+Previous versions of Squeal only supported definitions in the "public"
12+schema. Squeal 0.5 adds support for multiple schemas with the new kind
15+type SchemasType = [(Symbol,SchemaType)]
18+In order to upgrade your queries, manipulations and definitions from
19+Squeal 0.4, you will have to apply the `Public` type family, which indicates
20+that your only schema is the "public" schema.
24+setup :: Definition '[] Schema
27+setup :: Definition (Public '[]) (Public Schema)
30+You can create non-public schemas using `createSchema` and inversely
31+remove them using `dropSchema`. There is also an idempotent
32+`createSchemaIfNotExists`.
34+In order to handle aliases which may refer to non-public schemas, Squeal 0.5
35+introduces `QualifiedAlias`es. A `QualifiedAlias` can be referred to using
36+the `(!)` operator from the `IsQualified` typeclass; but if you want to refer
37+to an alias from the "public" schema, you can continue to use a single
38+overloaded label, no need to write `#public ! #tab`, just write `#tab`.
40+**Top-level statements**
42+As a consequence of multi-schema support, common table expressions that
43+a `Query` or `Manipulation` may refer to had to be broken into a new parameter.
44+Additionally, `Query` gained another new parameter for its outer scope which
45+will be discussed in the next section.
47+To simplify type signatures that you have to write for top-level queries
48+and manipulations, Squeal 0.5 introduces the `Query_` and `Manipulation_`
53+ (schemas :: SchemasType)
56+ Query_ schemas params row =
57+ Query '[] '[] schemas (TuplePG params) (RowPG row)
60+As you see, a top-level `Query_` has no outer scope and no common
61+table expressions in scope, they are empty `'[]`. Moreover,
62+its parameters and row parameters are now `Type`s, which are
63+converted to corresponding Postgres types using the `TuplePG`
64+and `RowPG` type families. This means you can write the type signatures
65+for your top-level statements using the Haskell types that you
66+intend to input and retrieve when running the statements. Similar
67+to `Query_`, there is a `Manipulation_` type, the only difference
68+being that a general `Manipulation` doesn't have an outer scope,
69+only a scope for common table expressions.
71+**Subquery expressions**
73+Previous versions of Squeal offered subquery expression support
74+but there were issues. The common use case of using the `IN` operator
75+from SQL was overly complex. There was a proliferation of subquery
76+functions to handle different comparison operators, each with two versions
77+for comparing `ALL` or `ANY` of the query rows. And, most confoundedly,
78+there was no way to support the `EXISTS` subquery because the "outer scope"
79+for a query was not available.
81+Squeal adds an outer scope to the `Query` type.
86+ (commons :: FromType)
87+ (schemas :: SchemasType)
88+ (params :: [NullityType])
90+ = UnsafeQuery { renderQuery :: ByteString }
93+This enables a well-typed `exists` function.
97+ :: Query (Join outer from) commons schemas params row
98+ -> Condition outer commons grp schemas params from
101+The `in_` and `notIn` functions were simplified to handle the most
102+common use case of comparing to a list of values.
106+ :: Expression outer commons grp schemas params from ty -- ^ expression
107+ -> [Expression outer commons grp schemas params from ty]
108+ -> Condition outer commons grp schemas params from
111+Finally, general subquery comparisons were abstracted to work with
112+any comparison operators, using the `Operator` type which will be discussed in
117+ :: Expression outer commons grp schemas params from ty1
118+ -> Operator ty1 ty2 ('Null 'PGbool)
119+ -> Query (Join outer from) commons schemas params '[col ::: ty2]
120+ -> Condition outer commons grp schemas params from
123+ :: Expression outer commons grp schemas params from ty1
124+ -> Operator ty1 ty2 ('Null 'PGbool)
125+ -> Query (Join outer from) commons schemas params '[col ::: ty2]
126+ -> Condition outer commons grp schemas params from
129+**Expression RankNTypes**
131+Squeal 0.5 introduces RankNType type synonyms for common expression patterns.
132+The simplest example is the `Expr` type, a type for "closed" expressions
133+that cannot reference any aliases or parameters.
137+ = forall outer commons grp schemas params from
138+ . Expression outer commons grp schemas params from x
141+There is also a function type `(-->)`, which is a subtype of the usual Haskell function
146+ = forall outer commons grp schemas params from
147+ . Expression outer commons grp schemas params from x
148+ -> Expression outer commons grp schemas params from y
151+We saw in the subquery section that there is an `Operator` type.
154+type Operator x1 x2 y
155+ = forall outer commons grp schemas params from
156+ . Expression outer commons grp schemas params from x1
157+ -> Expression outer commons grp schemas params from x2
158+ -> Expression outer commons grp schemas params from y
161+There are also types `FunctionN` and `FunctionVar` for n-ary functions
162+and variadic functions.
166+ = forall outer commons grp schemas params from
167+ . NP (Expression outer commons grp schemas params from) xs
168+ -> Expression outer commons grp schemas params from y
171+An n-ary function takes an `NP` list of `Expression`s as its argument.
172+Squeal 0.5 adds a helpful operator `(*:)`, to help scrap your `Nil`s.
173+You can construct an `NP` list now by using the operator `(:*)`,
174+until your last element, using `(*:)` there. For instance, the function
175+`atan2_` takes two arguments, `atan2_ (pi *: 2)`.
179+Previously, Squeal provided a couple versions of `SELECT` depending
180+on whether you wanted to select all columns of a unique table
181+in the from clause, i.e. `*`, all columns of a particular table
182+in the from clause, i.e. `.*`, or a list of columns from the from clause.
184+Squeal 0.5 refactors this pattern into a `Selection` GADT type, allowing
185+for abstraction and combinations that were not possible before.
188+data Selection outer commons grp schemas params from row where
190+ :: HasUnique tab from row
191+ => Selection outer commons 'Ungrouped schemas params from row
195+ -> Selection outer commons 'Ungrouped schemas params from row
198+ => NP (Aliased (Expression outer commons grp schemas params from)) row
199+ -> Selection outer commons grp schemas params from row
202+ => NP (Aliased (WindowFunction outer commons grp schemas params from)) row
203+ -> WindowDefinition outer commons grp schemas params from
204+ -> Selection outer commons grp schemas params from row
206+ :: Selection outer commons grp schemas params from right
207+ -> Selection outer commons grp schemas params from left
208+ -> Selection outer commons grp schemas params from (Join left right)
211+In addition to the `Star`, `DotStar` and `List` constructors, there is an
212+`Also` constructor combinator, which enables users to combine `Selection`s.
213+Additionally, there is an `Over` constructor that is used to enable
214+window functions, described in the next section.
216+To upgrade from Squeal 0.4, you will replace `selectStar` with `select Star`,
217+replace `selectDotStar #tab` with `select (DotStar #tab)`. The `List`
218+selection is such a common use case that there is a function `select_` which
219+automatically applies it, so to upgrade from Squeal 0.4, replace `select`
220+with `select_`. There are also independent `selectDistinct` and `selectDistinct_`
221+functions to filter out duplicate rows.
225+Previously, Squeal provided a couple versions of `INSERT` depending
226+on whether you wanted to insert `VALUES` or a query.
228+Squeal 0.5 refactors this pattern into a `QueryClause` GADT.
232+insertRow_ #tab (Set 2 `as` #col1 :* Default `as` #col2)
233+insertQuery_ #tab (selectStar (from (table #other_tab)))
236+insertInto_ #tab (Values_ (Set 2 `as` #col1 :* Default `as` #col2))
237+insertInto_ #tab (Subquery (select Star (from (table #other_tab))))
240+**Window functions and aggregation**
242+Previous versions of Squeal provided no support for window functions.
243+Squeal 0.5 adds support for window functions. We saw `Over` in the
249+ => NP (Aliased (WindowFunction outer commons grp schemas params from)) row
250+ -> WindowDefinition outer commons grp schemas params from
251+ -> Selection outer commons grp schemas params from row
254+`Over` combines window functions with window definitions. A `WindowDefinition`
255+is constructed using the `partitionBy` function, optionally with an `orderBy`
259+query :: Query_ (Public Schema) () (Row Int32 Int32)
261+ (#col1 & Also (rank `as` #col2 `Over` (partitionBy #col1 & orderBy [#col2 & Asc])))
265+Here the `rank` function is a `WindowFunction`
268+rank :: WinFun0 ('NotNull 'PGint8)
269+rank = UnsafeWindowFunction "rank()"
272+`WinFun0` is a RankNType, like `Expr` was, used for no argument window functions.
273+Similarly, there are also `WinFun1` and `WinFunN` types for
274+window functions and n-ary window functions.
276+In order to use the same syntax for certain window functions and aggregate functions,
277+a new typeclass `Aggregate` was introduced. So for instance, `sum_` can be
278+either a `Distinction` `Expression` or a `WindowFunction`, used either with
279+a `groupBy` or with a `partitionBy` in the appropriate way.
282+data Distinction (expr :: kind -> Type) (ty :: kind)
284+ | Distinct (expr ty)
287+Aggregate functions can be run over all rows or only over distinct rows,
288+while window functions bear no such distinction.
292+Thanks to [https://github.com/Raveline](Raveline) Squeal 0.5 introduces
293+a function `defaultMain` to easily create a command line program to
294+run or rewind your migrations.
296+Previously, Squeal's migrations were impure, allowing in addition to
297+running `Definition`s to run arbitrary `IO` operations, such as inserting
298+data into the database or printing out status messages. In order to
299+provide compatibility with other migration systems, Squeal 0.5 introduces
300+pure migrations, that is migrations that are only `Definition`s.
303+data Migration p schemas0 schemas1 = Migration
304+ { name :: Text -- ^ The `name` of a `Migration`.
305+ -- Each `name` in a `Migration` should be unique.
306+ , up :: p schemas0 schemas1 -- ^ The `up` instruction of a `Migration`.
307+ , down :: p schemas1 schemas0 -- ^ The `down` instruction of a `Migration`.
308+ } deriving (GHC.Generic)
311+A pure migration is a `Migration Definition`, a pair of inverse
312+`Definition`s with a unique name. To recover impure migrations, Squeal 0.5
313+introduces the `Terminally` type.
316+newtype Terminally trans monad x0 x1 = Terminally
317+ { runTerminally :: trans x0 x1 monad () }
320+`Terminally` applies the indexed monad transformer and the monad it transforms
321+to the unit type `()`, thereby turning an indexed monad into a `Category`. An
322+impure migration is a `Migration (Terminally PQ IO)`. You can always cast
323+a pure migration into an impure migration with the functor, `pureMigration`.
327+ :: Migration Definition schemas0 schemas1
328+ -> Migration (Terminally PQ IO) schemas0 schemas1
331+To run either pure or impure migrations, Squeal 0.5 introduces
332+a typeclass, `Migratory`.
335+class Category p => Migratory p where
338+ :: AlignedList (Migration p) schemas0 schemas1
339+ -> PQ schemas0 schemas1 IO ()
342+ :: AlignedList (Migration p) schemas0 schemas1
343+ -> PQ schemas1 schemas0 IO ()
346+The signatures of `migrateUp` and `migrateDown` have been changed
347+to make them easier to compose with other `PQ` actions.
351+You can now run transactions `ephemerally`, guaranteed to roll back,
352+but return the result or throw the exception that the transaction
353+would have generated. This is useful for testing. You can also
354+`transactionallyRetry` computations, retrying the transaction if
355+a [serialization failure](https://www.postgresql.org/docs/11/transaction-iso.html#XACT-REPEATABLE-READ) occurs.
359+Squeal now supports money via a `Money` Haskell `Type` and a `'PGmoney`
360+`PGType`. Squeal 0.5 also adds support for creating domain types
365+Squeal 0.5 adds support for new functions; `now`, `makeDate`, `makeTime`,
366+, `makeTimestamp`, and `makeTimestamptz`, a function `interval_` for
367+constructing time intervals out multiples of `TimeUnit`s, and a new
368+`TimeOp` class, defining affine space operators for time types and their
373+Squeal allows you to include Haskell values in your statements using
374+out of line `parameter`s, but often you want to include them inline,
375+as a SQL `literal`. Squeal 0.5 enables this using the `Literal` class.
377+**Set returning functions**
379+Squeal 0.5 adds support for set returning functions such as `unnest`,
380+with the `RankNType` `SetOfFunction`, which can be used as as a `FromClause`.
384+Squeal 0.5 adds extensive support for text search types, functions and operators.
388+Lots more changes went into and under the hood of the new version.
389+The `Expression` module was split into coherent submodules since it
390+had grown to immense proportions. New modules `Alias`, `PG` and `List`
391+were added to relieve some of the burden that the `Schema` module
392+had been carrying. Rendering has been better unified with a new
393+`RenderSQL` typeclass. Type level list concatenation with the `Additional`
394+typeclass has been added. `Manipulation`s `update` and `delete`
395+were upgraded, so you can leave out fields you don't want to update and
396+use `USING` clauses in deletes. Upserts which were previously broken
397+now work. The `IO` typeclass hierarchy was changed from `MonadBase`
398+and `MonadBaseControl` to `MonadIO` and `MonadUnliftIO`. A new
399+`withRecursive` `Manipulation` was added. `SquealException`s were
400+refactored and a `trySqueal` function added. Arrays were refactored.
401+And there was probably more I've forgotten.
405+Version 0.4 strengthens Squeal's type system, adds
406+support for multidimensional arrays, improves support
407+for container type, improves `with` statements,
408+improves runtime exceptions, accomodates SQL's three-valued logic,
409+adds subquery expressions, and adds table and view type expressions.
413+Squeal 0.4 renames some kinds to aid intuition:
416+type RowType = [(Symbol, NullityType)] -- previously RelationType
417+type FromType = [(Symbol, RowType)] -- previously RelationsType
420+Null safety for array and composite types is gained by having the base
421+type of an array be a `NullityType` and the base type of a composite
427+ | PGvararray NullityType
428+ | PGfixarray Nat NullityType
429+ | PGcomposite RowType
432+Squeal embeds Postgres types into Haskell using data kinds and type-in-type:
435+data PGType = PGbool | ..
436+data NullityType = Null PGType | NotNull PGType
437+type RowType = [(Symbol, NullityType)] -- previously RelationType
438+type FromType = [(Symbol, RowType)] -- previously RelationsType
441+In another sense, we can embed Haskell types
442+into Postgres types by providing type families:
445+type family PG (hask :: Type) :: PGType
446+type family NullPG (hask :: Type) :: NullityType
447+type family TuplePG (hask :: Type) :: [NullityType]
448+type family RowPG (hask :: Type) :: RowType
451+Let's look at these one by one.
453+`PG` was introduced in Squeal 0.3. It was a closed type family that
454+associates some Haskell types to their obvious corresponding Postgres
455+types like `PG Double = 'PGfloat8`. It only worked on base types,
456+no arrays or composites. Squeal 0.4 extends it to
457+such container types and makes it an open type family so that
458+users can make their own type instances.
460+`NullPG` had a different name before but it does the obvious
461+thing for Haskell with `Maybe`s:
464+type family NullPG hask where
465+ NullPG (Maybe hask) = 'Null (PG hask)
466+ NullPG hask = 'NotNull (PG hask)
469+`TuplePG` uses generics to turn tuple types (including records)
470+into lists of `NullityType`s in the logical way, e.g.
471+`TuplePG (Bool, Day) = '[ 'PGbool, 'PGdate]`.
473+`RowPG` also uses generics to turn record types into a `RowType` in the logical way, e.g.
476+>>> data Person = Person { name :: Text, age :: Int32 } deriving GHC.Generic
477+>>> instance SOP.Generic Person
478+>>> instance SOP.HasDatatypeInfo Person
479+>>> :kind! TuplePG Person
480+TuplePG Person :: [NullityType]
481+= '['NotNull 'PGtext, 'NotNull 'PGint4]
482+>>> :kind! RowPG Person
483+RowPG Person :: [(Symbol, NullityType)]
484+= '["name" ::: 'NotNull 'PGtext, "age" ::: 'NotNull 'PGint4]
487+We've already seen a hint of why these types are useful in one construction
488+from Squeal 0.3. Creating composite types in Postgres directly from a Haskell
489+record type essentially uses `RowPG`. Another important use is in simplifying
490+the type signatures for a `Query` or `Manipulation`. Very often, you will have
491+a tuple type corresponding to the parameters and a record type corresponding
492+to the returned columns of a `Query` or `Manipulation`. Instead of writing
493+boilerplate signature you can reuse these with the help of `TuplePG` and `RowPG`
500+ query :: Query '["user" ::: 'View (RowPG Person)] (TuplePG (Only Int32)) (RowPG Person)
501+ query = selectStar (from (view #user) & where_ (#age .> param @1))
507+In addition to being able to encode and decode basic Haskell types
508+like `Int16` and `Text`, Squeal 0.4 permits you to encode and decode Haskell types to
509+Postgres array types. The `Vector` type corresponds to to variable length arrays.
510+And thanks to an idea from [Mike Ledger](https://github.com/mikeplus64),
511+homogeneous tuples correspond to fixed length arrays. We can even
512+create multi-dimensional fixed length arrays. Let's see an example.
517+ { col1 :: Vector Int16
518+ , col2 :: (Maybe Int16,Maybe Int16)
519+ , col3 :: ((Int16,Int16),(Int16,Int16),(Int16,Int16))
520+ } deriving (Eq, GHC.Generic)
523+>>> instance Generic Row
524+>>> instance HasDatatypeInfo Row
527+Define a simple round trip query.
532+ roundTrip :: Query '[] (TuplePG Row) (RowPG Row)
533+ roundTrip = values_ $
534+ parameter @1 (int2 & vararray) `as` #col1 :*
535+ parameter @2 (int2 & fixarray @2) `as` #col2 :*
536+ parameter @3 (int2 & fixarray @2 & fixarray @3) `as` #col3
539+>>> :set -XOverloadedLists
540+>>> let input = Row [1,2] (Just 1,Nothing) ((1,2),(3,4),(5,6))
542+void . withConnection "host=localhost port=5432 dbname=exampledb" $ do
543+ result <- runQueryParams roundTrip input
544+ Just output <- firstRow result
545+ liftBase . print $ input == output
552+Squeal aims to provide a correspondence between Haskell types and Postgres types.
553+In particular, Haskell ADTs with nullary constructors can correspond to
554+Postgres enum types and Haskell record types can correspond to Postgres
555+composite types. However, it's not always obvious that that's how a user
556+will choose to store values of those types. So Squeal 0.4 introduces newtypes
557+whose purpose is to specify how a user wants to store values of a type.
560+newtype Json hask = Json {getJson :: hask}
561+newtype Jsonb hask = Jsonb {getJsonb :: hask}
562+newtype Composite record = Composite {getComposite :: record}
563+newtype Enumerated enum = Enumerated {getEnumerated :: enum}
566+Let's see an example:
569+>>> data Schwarma = Beef | Lamb | Chicken deriving (Eq, Show, GHC.Generic)
570+>>> instance SOP.Generic Schwarma
571+>>> instance SOP.HasDatatypeInfo Schwarma
573+>>> data Person = Person {name :: Text, age :: Int32} deriving (Eq, Show, GHC.Generic)
574+>>> instance SOP.Generic Person
575+>>> instance SOP.HasDatatypeInfo Person
576+>>> instance Aeson.FromJSON Person
577+>>> instance Aeson.ToJSON Person
580+We can create the equivalent Postgres types directly from their Haskell types.
585+ '[ "schwarma" ::: 'Typedef (PG (Enumerated Schwarma))
586+ , "person" ::: 'Typedef (PG (Composite Person))
592+ setup :: Definition '[] Schema
594+ createTypeEnumFrom @Schwarma #schwarma >>>
595+ createTypeCompositeFrom @Person #person
599+Let's demonstrate how to associate our Haskell types `Schwarma` and `Person`
600+with enumerated, composite or json types in Postgres. First create a Haskell
601+`Row` type using the `Enumerated`, `Composite` and `Json` newtypes as fields.
606+ { schwarma :: Enumerated Schwarma
607+ , person1 :: Composite Person
608+ , person2 :: Json Person
609+ } deriving (Eq, GHC.Generic)
612+>>> instance Generic Row
613+>>> instance HasDatatypeInfo Row
617+ (Enumerated Chicken)
618+ (Composite (Person "Faisal" 24))
619+ (Json (Person "Ahmad" 48))
623+Once again, define a round trip query.
628+ roundTrip :: Query Schema (TuplePG Row) (RowPG Row)
629+ roundTrip = values_ $
630+ parameter @1 (typedef #schwarma) `as` #schwarma :*
631+ parameter @2 (typedef #person) `as` #person1 :*
632+ parameter @3 json `as` #person2
636+Finally, we can drop our type definitions.
641+ teardown :: Definition Schema '[]
642+ teardown = dropType #schwarma >>> dropType #person
652+ result <- runQueryParams roundTrip input
653+ Just output <- firstRow result
654+ liftBase . print $ input == output
656+ void . withConnection "host=localhost port=5432 dbname=exampledb" $
659+ & pqThen (define teardown)
666+Squeal 0.3 supported WITH statements but there's a couple problems with them.
667+Here's the type signature for `with` in Squeal 0.3.
671+ :: SOP.SListI commons
672+ => NP (Aliased (Manipulation schema params)) (common ': commons)
673+ -- ^ common table expressions
674+ -> Manipulation (With (common ': commons) schema) params results
675+ -> Manipulation schema params results
678+The first problem is that `with` only works with `Manipulations`.
679+It can work on `Query`s by using `queryStatement` but it still will
680+return a `Manipulation`. We can fix this issue by making `with` a
681+method of a type class with instances for both `Query` and `Manipulation`.
683+The second problem is that all the common table expressions
684+refer the base schema, whereas in SQL, each subsequent CTE can
685+refer to previous CTEs as well. But this can be fixed! First define a datatype:
688+data CommonTableExpression statement params schema0 schema1 where
689+ CommonTableExpression
690+ :: Aliased (statement schema params) (alias ::: cte)
691+ -> CommonTableExpression statement params schema (alias ::: 'View cte ': schema)
694+It's just a wrapper around an aliased statement, where the statement
695+could be either a `Query` or `Manipulation`, but it augments the schema
696+by adding a view to it. It almost looks like a morphism between schemas
697+but there is no way yet to compose them. Luckily, Squeal already has
698+a datatype for this, which is used for migrations, the `AlignedList`
699+type which is really the "free category". So we can then define a `With` type class:
702+class With statement where
704+ :: AlignedList (CommonTableExpression statement params) schema0 schema1
705+ -> statement schema1 params row
706+ -> statement schema0 params row
709+By giving `Aliasable` instances to CTEs and aligned singleton lists of CTEs (i.e. scrap-your-nils), we get a nice syntax for WITH statements in Squeal.
711+Here's an example of using `with` for a `Query` and a `Manipulation`:
718+ '[ "c1" ::: 'NotNull 'PGtext
719+ , "c2" ::: 'NotNull 'PGtext] ]
721+ '[ "c1" ::: 'NotNull 'PGtext
722+ , "c2" ::: 'NotNull 'PGtext ]
724+ selectStar (from (view #t1)) `as` #t2 :>>
725+ selectStar (from (view #t2)) `as` #t3
726+ ) (selectStar (from (view #t3)))
729+WITH "t2" AS (SELECT * FROM "t1" AS "t1"), "t3" AS (SELECT * FROM "t2" AS "t2") SELECT * FROM "t3" AS "t3"
731+>>> type ProductsTable = '[] :=> '["product" ::: 'NoDef :=> 'NotNull 'PGtext, "date" ::: 'Def :=> 'NotNull 'PGdate]
735+ manipulation :: Manipulation
736+ '[ "products" ::: 'Table ProductsTable
737+ , "products_deleted" ::: 'Table ProductsTable
738+ ] '[ 'NotNull 'PGdate] '[]
740+ (deleteFrom #products (#date .< param @1) ReturningStar `as` #deleted_rows)
741+ (insertQuery_ #products_deleted (selectStar (from (view (#deleted_rows `as` #t)))))
742+in printSQL manipulation
744+WITH "deleted_rows" AS (DELETE FROM "products" WHERE ("date" < ($1 :: date)) RETURNING *) INSERT INTO "products_deleted" SELECT * FROM "deleted_rows" AS "t"
747+**Three Valued Logic**
749+In previous versions of Squeal, conditions followed classical two valued logic
750+of `true` and `false`.
754+type Condition schema from grouping params =
755+ Expression schema from grouping params ('NotNull 'PGbool)
758+I had thought that three valued logic, which is what SQL uses, was confusing.
759+However, multiple users reported being confused at being forced to do `NULL`
760+handling, particularly in their left joins. Since the original motivation
761+of being less confusing evaporated I decided to switch to three valued logic
762+of `true`, `false` and `null_`.
766+type Condition schema from grouping params =
767+ Expression schema from grouping params ('Null 'PGbool)
770+**Subquery Expressions**
772+Squeal 0.4 adds support for subquery expressions such as `IN` and `op ANY/ALL`.
776+Squeal 0.4 adds functions to define type expressions from tables and views
777+and a type expression for user defined types, `typetable`, `typeview` and
780+**Runtime Exceptions**
782+Squeal now has an exception type which gives details on the sort of error
783+encountered and handler functions.
788+ { sqlExecStatus :: LibPQ.ExecStatus
789+ , sqlStateCode :: Maybe ByteString
790+ -- ^ https://www.postgresql.org/docs/current/static/errcodes-appendix.html
791+ , sqlErrorMessage :: Maybe ByteString
793+ | ResultException Text
794+ | ParseException Text
796+instance Exception SquealException
799+ :: MonadBaseControl IO io
801+ -> (SquealException -> io a) -- ^ handler
805+ :: MonadBaseControl IO io
806+ => (SquealException -> io a) -- ^ handler
810+**Additional Changes**
812+Squeal 0.4 adds `field` and `index` functions to get components of composite
813+and array expressions.
815+Squeal 0.4 adds a dependency on `records-sop` to offload a lot of boilerplate
816+type family logic that was needed for `RowPG`.
818+The above changes required major and minor changes to Squeal DSL functions.
819+Please consult the documentation.
821+### Version 0.3.2 - August 4, 2018
823+Version 0.3.2 features extensive support for `JSON` functionality with
824+more than 50 new functions.
825+This work is entirely due to [Mike Ledger](https://github.com/mikeplus64)
826+who has been making terrific contributions to Squeal. Thanks!
827+We also got some examples in the documentation for pools submitted by
828+[Raveline](https://github.com/Raveline). I'm so pleased to be
829+getting pull requests and issue submissions from you all!
831+### Version 0.3.1 - July 7, 2018
833+Version 0.3.1 of Squeal enables the "Scrap your Nils" trick for
834+heterogeneous lists of `Alias`es, `Aliased` expressions, `PGlabel`s and `By`s
835+with the typeclasses `IsLabel`, `IsQualified`, `IsPGlabel`,
836+and the new `Aliasable` typeclass, to eliminate all need of using `Nil` in a list.
837+There were a couple minor name changes, i.e. the function `group` was renamed to `groupBy`.
838+Please consult the documentation.
840+### Version 0.3 - June 26, 2018
842+Version 0.3 of Squeal adds views as well as composite and enumerated types to Squeal.
843+To support these features, a new kind `SchemumType` was added.
852+As a consequence, you will have to update your schema definitions like so:
858+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
859+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
860+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
866+ '[ "users" ::: 'Table (
867+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
868+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
869+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext
876+You can now create, drop, and query views.
881+ ('[] :: TableConstraints) :=>
882+ '[ "a" ::: 'NoDef :=> 'Null 'PGint4
883+ , "b" ::: 'NoDef :=> 'Null 'PGint4
884+ , "c" ::: 'NoDef :=> 'Null 'PGint4
887+ '[ "b" ::: 'Null 'PGint4
888+ , "c" ::: 'Null 'PGint4
894+ definition :: Definition '["abc" ::: 'Table ABC ] '["abc" ::: 'Table ABC, "bc" ::: 'View BC]
895+ definition = createView #bc (select (#b :* #c :* Nil) (from (table #abc)))
896+in printSQL definition
898+CREATE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";
902+ definition :: Definition '["abc" ::: 'Table ABC, "bc" ::: 'View BC] '["abc" ::: 'Table ABC]
903+ definition = dropView #bc
904+in printSQL definition
910+ query :: Query '["abc" ::: 'Table ABC, "bc" ::: 'View BC] '[] BC
911+ query = selectStar (from (view #bc))
914+SELECT * FROM "bc" AS "bc"
919+PostgreSQL has a powerful type system. It even allows for user defined types.
920+For instance, you can define enumerated types which are data types that comprise
921+a static, ordered set of values. They are equivalent to Haskell algebraic data
922+types whose constructors are nullary. An example of an enum type might be the days of the week,
923+or a set of status values for a piece of data.
925+Enumerated types are created using the `createTypeEnum` command, for example:
930+ definition :: Definition '[] '["mood" ::: 'Typedef ('PGenum '["sad", "ok", "happy"])]
931+ definition = createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy" :* Nil)
933+>>> printSQL definition
934+CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');
937+Enumerated types can also be generated from a Haskell algebraic data type with nullary constructors, for example:
940+>>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
941+>>> instance SOP.Generic Schwarma
942+>>> instance SOP.HasDatatypeInfo Schwarma
944+>>> :kind! EnumFrom Schwarma
945+EnumFrom Schwarma :: PGType
946+= 'PGenum '["Beef", "Lamb", "Chicken"]
950+ definition :: Definition '[] '["schwarma" ::: 'Typedef (EnumFrom Schwarma)]
951+ definition = createTypeEnumFrom @Schwarma #schwarma
953+>>> printSQL definition
954+CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');
957+You can express values of an enum type using `label`, which is an overloaded method
958+of the `IsPGlabel` typeclass.
963+ expression :: Expression sch rels grp params ('NotNull (EnumFrom Schwarma))
964+ expression = label @"Chicken"
965+in printSQL expression
972+In addition to enum types, you can define composite types.
973+A composite type represents the structure of a row or record;
974+it is essentially just a list of field names and their data types.
977+`createTypeComposite` creates a composite type. The composite type is
978+specified by a list of attribute names and data types.
983+ definition :: Definition '[] '["complex" ::: 'Typedef ('PGcomposite '["real" ::: 'PGfloat8, "imaginary" ::: 'PGfloat8])]
984+ definition = createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
986+>>> printSQL definition
987+CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
990+Composite types are almost equivalent to Haskell record types.
991+However, because of the potential presence of `NULL`
992+all the record fields must be `Maybe`s of basic types.
993+Composite types can be generated from a Haskell record type, for example:
996+>>> data Complex = Complex {real :: Maybe Double, imaginary :: Maybe Double} deriving GHC.Generic
997+>>> instance SOP.Generic Complex
998+>>> instance SOP.HasDatatypeInfo Complex
1000+>>> :kind! CompositeFrom Complex
1001+CompositeFrom Complex :: PGType
1002+= 'PGcomposite '['("real", 'PGfloat8), '("imaginary", 'PGfloat8)]
1006+ definition :: Definition '[] '["complex" ::: 'Typedef (CompositeFrom Complex)]
1007+ definition = createTypeCompositeFrom @Complex #complex
1008+in printSQL definition
1010+CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
1013+A row constructor is an expression that builds a row value
1014+(also called a composite value) using values for its member fields.
1019+ i :: Expression '[] '[] 'Ungrouped '[] ('NotNull (CompositeFrom Complex))
1020+ i = row (0 `As` #real :* 1 `As` #imaginary :* Nil)
1026+You can also use `(&)` to apply a field label to a composite value.
1031+ expr :: Expression '[] '[] 'Ungrouped '[] ('Null 'PGfloat8)
1032+ expr = i & #imaginary
1035+(ROW(0, 1)).imaginary
1038+Both composite and enum types can be automatically encoded from and decoded to their equivalent Haskell types.
1039+And they can be dropped.
1044+ definition :: Definition '["mood" ::: 'Typedef ('PGenum '["sad", "ok", "happy"])] '[]
1045+ definition = dropType #mood
1047+>>> printSQL definition
1051+**Additional Changes**
1053+Squeal 0.3 also introduces a typeclass `HasAll` similar to `Has` but for a list of aliases.
1054+This makes it possible to clean up some unfortunately messy Squeal 0.2 definitions.
1058+>>> unique (Column #a :* Column #b :* Nil)
1061+>>> unique (#a :* #b :* Nil)
1064+Squeal 0.3 also adds `IsLabel` instances for `Aliased` expressions and tables as well as
1065+heterogeneous lists, allowing for some more economy of code.
1068+-- Squeal 0.2 (or 0.3)
1069+>>> select (#a `As` #a :* Nil) (from (table (#t `As` #t)))
1072+>>> select #a (from (table #t))
1075+Squeal 0.3 also fixes a bug that prevented joined queries on self-referencing tables.
1077+The above changes required major and minor changes to Squeal DSL functions.
1078+Please consult the documentation.
1080+### Version 0.2.1 - April 7, 2018
1082+This minor update fixes an issue where alias identifiers could conflict with
1083+reserved words in PostgreSQL. To fix the issue, alias identifiers are now
1084+quoted. Thanks to Petter Rasmussen for the fix.
1086+### Version 0.2 - March 26, 2018
1089+- **Constraints** - Type level table constraints like primary and foreign keys and column constraints like having `DEFAULT`.
1090+- **Migrations** - Support for linear, invertible migrations tracked in an auxiliary table
1091+- **Arrays** - Support for fixed- and variable-length arrays
1092+- **Aliases** - Generalized `Has` constraint
1093+- **Pools** - Support for pooled connections
1094+- **Transactions** - Support for transaction control language
1095+- **Queries, Manipulations, Definitions** - Small and large changes to Squeal's DSL
1097+Well, a lot of things changed!
1101+An important request was to bring constraints to the type level.
1102+This means that more of the schema is statically known. In `0.1` column constraints - which boil down
1103+to having `DEFAULT` or not - were at the type level, but they were confusingly named.
1106+0.1: 'Optional ('NotNull 'PGInt4)
1107+0.2: 'Def :=> 'NotNull 'PGInt4
1108+0.1: 'Required ('NotNull 'PGInt4)
1109+0.2: 'NoDef :=> 'NotNull 'PGInt4
1112+The `:=>` type operator is intended to helpfully connote a constraint relation.
1113+It's also used for table constraints which are new in `0.2`.
1117+ '[ "pk_emails" ::: 'PrimaryKey '["id"]
1118+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
1120+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4
1121+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
1122+ , "email" ::: 'NoDef :=> 'Null 'PGtext
1126+Another change in the constraint system was the removal of column constraints from
1127+query and manipulation results, as result columns don't support a notion of `DEFAULT`.
1128+This necessitates a distinction between `TableType`s which have both column and table
1129+constraints and `RelationType`s which have neither.
1133+Migrations are a hot topic and many people have requested this feature. Squeal `0.2`
1134+adds support for linear, invertible migrations. That is, a migration is a named,
1135+invertible, schema-tracking computation:
1138+data Migration io schema0 schema1 = Migration
1139+ { name :: Text -- ^ The `name` of a `Migration`.
1140+ -- Each `name` in a `Migration` should be unique.
1141+ , up :: PQ schema0 schema1 io () -- ^ The `up` instruction of a `Migration`.
1142+ , down :: PQ schema1 schema0 io () -- ^ The `down` instruction of a `Migration`.
1146+And, `Migration`s can be put together in an "aligned" list:
1149+data AlignedList p x0 x1 where
1150+ Done :: AlignedList p x x
1151+ (:>>) :: p x0 x1 -> AlignedList p x1 x2 -> AlignedList p x0 x2
1154+These aligned lists are free categories and might look familiar from
1155+the [reflections without remorse](http://okmij.org/ftp/Haskell/zseq.pdf) technique,
1156+which uses their cousins, aligned sequences.
1158+In the context of migration, they allow one to chain new migrations as a
1159+schema evolves over time. `Migration`s' execution is tracked in an auxiliary
1160+migrations table. Migration lists can then be run or rewinded.
1164+ :: MonadBaseControl IO io
1165+ => AlignedList (Migration io) schema0 schema1 -- ^ migrations to run
1167+ ("schema_migrations" ::: MigrationsTable ': schema0)
1168+ ("schema_migrations" ::: MigrationsTable ': schema1)
1172+ :: MonadBaseControl IO io
1173+ => AlignedList (Migration io) schema0 schema1 -- ^ migrations to rewind
1175+ ("schema_migrations" ::: MigrationsTable ': schema1)
1176+ ("schema_migrations" ::: MigrationsTable ': schema0)
1182+In Squeal `0.1`, we had different typeclasses `HasColumn` and `HasTable` to indicate
1183+that a table has a column or that a schema has a table. In Squeal `0.2` this has been
1184+unified to a single typeclass,
1187+class KnownSymbol alias =>
1188+ Has (alias :: Symbol) (fields :: [(Symbol,kind)]) (field :: kind)
1189+ | alias fields -> field where
1194+Support for array types has been added to Squeal `0.2` through
1195+the `'PGfixarray` and `'PGvararray` `PGType`s. Array values can be
1196+constructed using the `array` function and can be encoded from and decoded to
1201+Squeal `0.2` provides a monad transformer `PoolPQ` that's an instance of `MonadPQ`.
1202+The `resource-pool` library is leveraged to provide striped pools of `Connection`s.
1203+`PoolPQ` should be a drop in replacement for running `Manipulation`s and `Query`s with
1208+Squeal `0.2` supports a simple transaction control language. A computation in
1209+`MonadPQ` can be called `transactionally` with different levels of isolation.
1210+Additionally, a schema changing computation, a data definition, can be run in a
1211+transaction. Running a computation in a transaction means that all SQL statements
1212+will be rolled back if an exception is encountered.
1214+**Queries, Manipulations and Definitions**
1216+The above changes required major and minor changes to Squeal DSL functions.
1217+Please consult the documentation.