@@ -1,1217 +0,0 @@
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.