on dev help sign in
doooocks
commit1086cfcd4436e8a71431b0161696b28cbe767e96 authorEitan Chatav <eitan@Eitans-MacBook-Pro.local> dateFri 12 Apr 2019, 20:09 (8 years ago) parent756a427
10 files changed+153−54
squeal-postgresql/squeal-postgresql.cabal+1−1 squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs−1 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Aggregate.hs+11−1 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Collection.hs+3−3 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Comparison.hs+23−8 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Json.hs+26−29 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Literal.hs+10 squeal-postgresql/src/Squeal/PostgreSQL/Expression/SetOf.hs+43−9 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Subquery.hs+13−2 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Window.hs+23
squeal-postgresql/squeal-postgresql.cabal+1−1
@@ -54,7 +54,7 @@ library
5454 Squeal.PostgreSQL.Schema
5555 Squeal.PostgreSQL.Transaction
5656 default-language: Haskell2010
57− ghc-options: -Wall
57+ ghc-options: -Wall -Werror
5858 build-depends:
5959 aeson >= 1.2.4.0
6060 , base >= 4.11.1.0 && < 5.0
squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs−1
@@ -8,7 +8,6 @@ Stability: experimental
88Squeal expressions are the atoms used to build statements.
99-}
1010
11−{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
1211{-# LANGUAGE
1312 AllowAmbiguousTypes
1413 , ConstraintKinds
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Aggregate.hs+11−1
@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Expression.Aggregate
3+Description: Aggregate functions
4+Copyright: (c) Eitan Chatav, 2019
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Aggregate functions
9+-}
10+
111{-# LANGUAGE
212 DataKinds
313 , DeriveGeneric
@@ -39,7 +49,7 @@ import Squeal.PostgreSQL.Schema
3949{- |
4050`Aggregate` functions compute a single result from a set of input values.
4151`Aggregate` functions can be used as `GroupedBy` `Expression`s as well
42−as `WindowFunction`s.
52+as `Squeal.PostgreSQL.Expression.Window.WindowFunction`s.
4353-}
4454class Aggregate expr1 exprN aggr
4555 | aggr -> expr1, aggr -> exprN where
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Collection.hs+3−3
@@ -4,6 +4,7 @@
44 , FlexibleContexts
55 , FlexibleInstances
66 , MultiParamTypeClasses
7+ , OverloadedLabels
78 , OverloadedStrings
89 , RankNTypes
910 , ScopedTypeVariables
@@ -112,9 +113,8 @@ index n expr = UnsafeExpression $
112113 parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"
113114
114115-- | Expand an array to a set of rows
115−unnest
116− :: SetOfFunction (null ('PGvararray ty)) '["unnest" ::: '["unnest" ::: ty]]
117−unnest = unsafeSetOfFunction "unnest"
116+unnest :: SetOfFunction "unnest" (null ('PGvararray ty)) '["unnest" ::: ty]
117+unnest = unsafeSetOfFunction #unnest
118118
119119-- | A row constructor is an expression that builds a row value
120120-- (also called a composite value) using values for its member fields.
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Comparison.hs+23−8
@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Expression.Comparison
3+Description: Comparison expressions
4+Copyright: (c) Eitan Chatav, 2019
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Comparison functions and operators
9+-}
10+
111{-# LANGUAGE
212 OverloadedStrings
313 , RankNTypes
@@ -29,6 +39,8 @@ module Squeal.PostgreSQL.Expression.Comparison
2939 , isNotUnknown
3040 ) where
3141
42+import Data.ByteString
43+
3244import Squeal.PostgreSQL.Expression
3345import Squeal.PostgreSQL.Expression.Logic
3446import Squeal.PostgreSQL.Render
@@ -87,6 +99,9 @@ greatest = unsafeFunctionVar "GREATEST"
8799least :: FunctionVar ty ty ty
88100least = unsafeFunctionVar "LEAST"
89101
102+{- |
103+A @RankNType@ for comparison expressions like `between`.
104+-}
90105type BetweenExpr
91106 = forall outer commons grp schemas params from ty
92107 . Expression outer commons grp schemas params from ty
@@ -94,19 +109,21 @@ type BetweenExpr
94109 , Expression outer commons grp schemas params from ty ) -- ^ bounds
95110 -> Condition outer commons grp schemas params from
96111
112+unsafeBetweenExpr :: ByteString -> BetweenExpr
113+unsafeBetweenExpr fun a (x,y) = UnsafeExpression $
114+ renderSQL a <+> fun <+> renderSQL x <+> "AND" <+> renderSQL y
115+
97116{- | >>> printSQL $ true `between` (null_, false)
98117TRUE BETWEEN NULL AND FALSE
99118-}
100119between :: BetweenExpr
101−between a (x,y) = UnsafeExpression $ renderSQL a <+> "BETWEEN"
102− <+> renderSQL x <+> "AND" <+> renderSQL y
120+between = unsafeBetweenExpr "BETWEEN"
103121
104122{- | >>> printSQL $ true `notBetween` (null_, false)
105123TRUE NOT BETWEEN NULL AND FALSE
106124-}
107125notBetween :: BetweenExpr
108−notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
109− <+> renderSQL x <+> "AND" <+> renderSQL y
126+notBetween = unsafeBetweenExpr "NOT BETWEEN"
110127
111128{- | between, after sorting the comparison values
112129
@@ -114,8 +131,7 @@ notBetween a (x,y) = UnsafeExpression $ renderSQL a <+> "NOT BETWEEN"
114131TRUE BETWEEN SYMMETRIC NULL AND FALSE
115132-}
116133betweenSymmetric :: BetweenExpr
117−betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
118− <+> "BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
134+betweenSymmetric = unsafeBetweenExpr "BETWEEN SYMMETRIC"
119135
120136{- | not between, after sorting the comparison values
121137
@@ -123,8 +139,7 @@ betweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
123139TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE
124140-}
125141notBetweenSymmetric :: BetweenExpr
126−notBetweenSymmetric a (x,y) = UnsafeExpression $ renderSQL a
127− <+> "NOT BETWEEN SYMMETRIC" <+> renderSQL x <+> "AND" <+> renderSQL y
142+notBetweenSymmetric = unsafeBetweenExpr "NOT BETWEEN SYMMETRIC"
128143
129144{- | not equal, treating null like an ordinary value
130145
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Json.hs+26−29
@@ -6,6 +6,9 @@
66 , OverloadedLabels
77 , OverloadedStrings
88 , PolyKinds
9+ , RankNTypes
10+ , ScopedTypeVariables
11+ , TypeApplications
912 , TypeOperators
1013 , UndecidableInstances
1114#-}
@@ -380,69 +383,63 @@ jsonbPretty = unsafeFunction "jsonb_pretty"
380383-- >>> import Data.Aeson
381384-- >>> printSQL (select Star (from (jsonEach (literal (Json (object ["a" .= "foo", "b" .= "bar"]))))))
382385-- SELECT * FROM json_each(('{"a":"foo","b":"bar"}' :: json))
383−jsonEach
384− :: Expression outer commons 'Ungrouped schemas params '[] (nullity 'PGjson) -- ^ json object
385− -> FromClause outer commons schemas params
386− '["json_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]]
387−jsonEach = unsafeSetOfFunction "json_each"
386+jsonEach :: SetOfFunction "json_each" (null 'PGjson)
387+ '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
388+jsonEach = unsafeSetOfFunction #json_each
388389
389390-- | Expands the outermost binary JSON object into a set of key/value pairs.
390391-- >>> import Data.Aeson
391392-- >>> printSQL (select Star (from (jsonbEach (literal (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))))
392393-- SELECT * FROM jsonb_each(('{"a":"foo","b":"bar"}' :: jsonb))
393394jsonbEach
394− :: Expression outer commons 'Ungrouped schemas params '[] (nullity 'PGjsonb) -- ^ jsonb object
395− -> FromClause outer commons schemas params
396− '["jsonb_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]]
397−jsonbEach = unsafeSetOfFunction "jsonb_each"
395+ :: SetOfFunction "jsonb_each" (nullity 'PGjsonb)
396+ '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
397+jsonbEach = unsafeSetOfFunction #jsonb_each
398398
399399-- | Expands the outermost JSON object into a set of key/value pairs.-- | Expands the outermost binary JSON object into a set of key/value pairs.
400400-- >>> import Data.Aeson
401401-- >>> printSQL (select Star (from (jsonEachText (literal (Json (object ["a" .= "foo", "b" .= "bar"]))))))
402402-- SELECT * FROM json_each_text(('{"a":"foo","b":"bar"}' :: json))
403403jsonEachText
404− :: Expression outer commons 'Ungrouped schemas params '[] (nullity 'PGjson) -- ^ json object
405− -> FromClause outer commons schemas params
406− '["json_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]]
407−jsonEachText = unsafeSetOfFunction "json_each_text"
404+ :: SetOfFunction "json_each_text" (null 'PGjson)
405+ '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
406+jsonEachText = unsafeSetOfFunction #json_each_text
408407
409408-- | Expands the outermost binary JSON object into a set of key/value pairs.
410409-- >>> import Data.Aeson
411410-- >>> printSQL (select Star (from (jsonbEachText (literal (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))))
412411-- SELECT * FROM jsonb_each_text(('{"a":"foo","b":"bar"}' :: jsonb))
413412jsonbEachText
414− :: Expression outer commons 'Ungrouped schemas params '[] (nullity 'PGjsonb) -- ^ jsonb object
415− -> FromClause outer commons schemas params
416− '["jsonb_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]]
417−jsonbEachText = unsafeSetOfFunction "jsonb_each_text"
413+ :: SetOfFunction "jsonb_each_text" (null 'PGjsonb)
414+ '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
415+jsonbEachText = unsafeSetOfFunction #jsonb_each_text
418416
419417-- | Returns set of keys in the outermost JSON object.
420418-- >>> import Data.Aeson
421419-- >>> printSQL (jsonObjectKeys (literal (Json (object ["a" .= "foo", "b" .= "bar"]))))
422420-- json_object_keys(('{"a":"foo","b":"bar"}' :: json))
423421jsonObjectKeys
424− :: Expression outer commons 'Ungrouped schemas params '[] (nullity 'PGjson) -- ^ json object
425− -> FromClause outer commons schemas params
426− '["json_object_keys" ::: '["json_object_keys" ::: 'NotNull 'PGtext]]
427−jsonObjectKeys = unsafeSetOfFunction "json_object_keys"
422+ :: SetOfFunction "json_object_keys" (nullity 'PGjson)
423+ '["json_object_keys" ::: 'NotNull 'PGtext]
424+jsonObjectKeys = unsafeSetOfFunction #json_object_keys
428425
429426-- | Returns set of keys in the outermost JSON object.
430427-- >>> import Data.Aeson
431428-- >>> printSQL (jsonbObjectKeys (literal (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))
432429-- jsonb_object_keys(('{"a":"foo","b":"bar"}' :: jsonb))
433430jsonbObjectKeys
434− :: Expression outer commons 'Ungrouped schemas params '[] (nullity 'PGjsonb) -- ^ jsonb object
435− -> FromClause outer commons schemas params
436− '["jsonb_object_keys" ::: '["jsonb_object_keys" ::: 'NotNull 'PGtext]]
437−jsonbObjectKeys = unsafeSetOfFunction "jsonb_object_keys"
431+ :: SetOfFunction "jsonb_object_keys" (null 'PGjsonb)
432+ '["jsonb_object_keys" ::: 'NotNull 'PGtext]
433+jsonbObjectKeys = unsafeSetOfFunction #jsonb_object_keys
438434
439435unsafePopulateFunction
440− :: KnownSymbol fun
436+ :: forall fun schemas null outer commons params ty row
437+ . KnownSymbol fun
441438 => Alias fun
442− -> TypeExpression schemas (nullity ('PGcomposite row))
443− -> Expression outer commons 'Ungrouped schemas params '[] ty
439+ -> TypeExpression schemas (null ('PGcomposite row))
440+ -> Expression outer commons 'Ungrouped schemas params '[] ty
444441 -> FromClause outer commons schemas params '[fun ::: row]
445−unsafePopulateFunction fun ty expr = UnsafeFromClause $ renderSQL fun
442+unsafePopulateFunction _fun ty expr = UnsafeFromClause $ renderSymbol @fun
446443 <> parenthesized ("null::" <> renderSQL ty <> ", " <> renderSQL expr)
447444
448445-- | Expands the JSON expression to a row whose columns match the record
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Literal.hs+10
@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Expression.Literal
3+Description: Literal expressions
4+Copyright: (c) Eitan Chatav, 2019
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Literal expressions
9+-}
10+
111{-# LANGUAGE
212 FlexibleContexts
313 , FlexibleInstances
squeal-postgresql/src/Squeal/PostgreSQL/Expression/SetOf.hs+43−9
@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Expression.SetOf
3+Description: Set returning functions
4+Copyright: (c) Eitan Chatav, 2019
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Set returning functions
9+-}
10+
111{-# LANGUAGE
212 AllowAmbiguousTypes
313 , DataKinds
@@ -5,20 +15,23 @@
515 , OverloadedStrings
616 , PolyKinds
717 , RankNTypes
18+ , ScopedTypeVariables
19+ , TypeApplications
820 , TypeOperators
921#-}
1022
1123module Squeal.PostgreSQL.Expression.SetOf
12− ( SetOfFunction
24+ ( generateSeries
25+ , generateSeriesStep
26+ , generateSeriesTimestamp
27+ , SetOfFunction
1328 , unsafeSetOfFunction
1429 , SetOfFunctionN
1530 , unsafeSetOfFunctionN
16− , generateSeries
17− , generateSeriesStep
18− , generateSeriesTimestamp
1931 ) where
2032
2133import Data.ByteString (ByteString)
34+import GHC.TypeLits
2235
2336import qualified Generics.SOP as SOP
2437
@@ -29,20 +42,32 @@ import Squeal.PostgreSQL.Render
2942import Squeal.PostgreSQL.Query
3043import Squeal.PostgreSQL.Schema
3144
32−type SetOfFunction ty setof
45+{- |
46+A @RankNType@ for set returning functions with 1 argument.
47+-}
48+type SetOfFunction fun ty setof
3349 = forall outer commons schemas params
3450 . Expression outer commons 'Ungrouped schemas params '[] ty
35− -> FromClause outer commons schemas params setof
51+ -> FromClause outer commons schemas params '[fun ::: setof]
3652
37−unsafeSetOfFunction :: ByteString -> SetOfFunction ty setof
38−unsafeSetOfFunction fun x = UnsafeFromClause $
39− fun <> parenthesized (renderSQL x)
53+-- | Escape hatch for a set returning function with 1 argument.
54+unsafeSetOfFunction
55+ :: forall fun ty setof
56+ . KnownSymbol fun
57+ => Alias fun
58+ -> SetOfFunction fun ty setof
59+unsafeSetOfFunction _fun x = UnsafeFromClause $
60+ renderSymbol @fun <> parenthesized (renderSQL x)
4061
62+{- |
63+A @RankNType@ for set returning functions with multiple argument.
64+-}
4165type SetOfFunctionN tys setof
4266 = forall outer commons schemas params
4367 . NP (Expression outer commons 'Ungrouped schemas params '[]) tys
4468 -> FromClause outer commons schemas params setof
4569
70+-- | Escape hatch for a set returning function with multiple argument.
4671unsafeSetOfFunctionN
4772 :: SOP.SListI tys
4873 => ByteString
@@ -50,18 +75,27 @@ unsafeSetOfFunctionN
5075unsafeSetOfFunctionN fun xs = UnsafeFromClause $
5176 fun <> parenthesized (renderCommaSeparated renderSQL xs)
5277
78+{- | @generateSeries (start *: stop)@
79+Generate a series of values, from @start@ to @stop@ with a step size of one
80+-}
5381generateSeries
5482 :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric]
5583 => SetOfFunctionN '[ null ty, null ty]
5684 '["generate_series" ::: '["generate_series" ::: '[null ty]]]
5785generateSeries = unsafeSetOfFunctionN "generate_series"
5886
87+{- | @generateSeries (start :* stop *: step)@
88+Generate a series of values, from @start@ to @stop@ with a step size of @step@
89+-}
5990generateSeriesStep
6091 :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric]
6192 => SetOfFunctionN '[null ty, null ty, null ty]
6293 '["generate_series" ::: '["generate_series" ::: '[null ty]]]
6394generateSeriesStep = unsafeSetOfFunctionN "generate_series"
6495
96+{- | @generateSeries (start :* stop *: step)@
97+Generate a series of values, from @start@ to @stop@ with a step size of @step@
98+-}
6599generateSeriesTimestamp
66100 :: ty `In` '[ 'PGtimestamp, 'PGtimestamptz]
67101 => SetOfFunctionN '[null ty, null ty, null 'PGinterval]
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Subquery.hs+13−2
@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Expression.Subquery
3+Description: Subquery expressions
4+Copyright: (c) Eitan Chatav, 2019
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Subquery expressions
9+-}
10+
111{-# LANGUAGE
212 DataKinds
313 , OverloadedStrings
@@ -49,8 +59,9 @@ row of the subquery result using the given `Operator`,
4959which must yield a Boolean result. The result of `subAll` is `true`
5060if all rows yield true (including the case where the subquery returns no rows).
5161The result is `false` if any `false` result is found.
52−The result is `null_` if no comparison with a subquery row returns `false`,
53−and at least one comparison returns `null_`.
62+The result is `Squeal.PostgreSQL.Expression.Null.null_` if
63+ no comparison with a subquery row returns `false`,
64+and at least one comparison returns `Squeal.PostgreSQL.Expression.Null.null_`.
5465
5566>>> printSQL $ subAll true (.==) (values_ (true `as` #foo))
5667(TRUE = ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo")))
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Window.hs+23
@@ -1,3 +1,13 @@
1+{-|
2+Module: Squeal.PostgreSQL.Expression.Window
3+Description: Window functions
4+Copyright: (c) Eitan Chatav, 2019
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+Window functions and definitions
9+-}
10+
111{-# LANGUAGE
212 DataKinds
313 , DeriveGeneric
@@ -27,6 +37,9 @@ module Squeal.PostgreSQL.Expression.Window
2737 , firstValue
2838 , lastValue
2939 , nthValue
40+ , WinFun0
41+ , WinFun1
42+ , WinFunN
3043 ) where
3144
3245import Control.DeepSeq
@@ -142,11 +155,17 @@ newtype WindowFunction
142155instance RenderSQL (WindowFunction outer commons grp schemas params from ty) where
143156 renderSQL = renderWindowFunction
144157
158+{- |
159+A @RankNType@ for window functions with no arguments.
160+-}
145161type WinFun0 x
146162 = forall outer commons grp schemas params from
147163 . WindowFunction outer commons grp schemas params from x
148164 -- ^ cannot reference aliases
149165
166+{- |
167+A @RankNType@ for window functions with 1 argument.
168+-}
150169type WinFun1 x y
151170 = forall outer commons grp schemas params from
152171 . Expression outer commons grp schemas params from x
@@ -154,6 +173,10 @@ type WinFun1 x y
154173 -> WindowFunction outer commons grp schemas params from y
155174 -- ^ output
156175
176+{- | A @RankNType@ for window functions with a fixed-length
177+list of heterogeneous arguments.
178+Use the `*:` operator to end your argument lists.
179+-}
157180type WinFunN xs y
158181 = forall outer commons grp schemas params from
159182 . NP (Expression outer commons grp schemas params from) xs