on dev help sign in
types & params
commit6a37c51c7cd617812e30e45d78a9b7b4740c0d13 authorEitan Chatav <eitan@Eitans-MacBook-Pro.local> dateSat 6 Apr 2019, 14:19 (8 years ago) parent460c628
7 files changed+353−287
squeal-postgresql/squeal-postgresql.cabal+2 squeal-postgresql/src/Squeal/PostgreSQL.hs+4 squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+1 squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+4−287 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Parameter.hs+70 squeal-postgresql/src/Squeal/PostgreSQL/Expression/Type.hs+271 squeal-postgresql/src/Squeal/PostgreSQL/Query.hs+1
squeal-postgresql/squeal-postgresql.cabal+2
@@ -33,10 +33,12 @@ library
3333 Squeal.PostgreSQL.Expression.Logic
3434 Squeal.PostgreSQL.Expression.Math
3535 Squeal.PostgreSQL.Expression.Null
36+ Squeal.PostgreSQL.Expression.Parameter
3637 Squeal.PostgreSQL.Expression.Sort
3738 Squeal.PostgreSQL.Expression.Text
3839 Squeal.PostgreSQL.Expression.TextSearch
3940 Squeal.PostgreSQL.Expression.Time
41+ Squeal.PostgreSQL.Expression.Type
4042 Squeal.PostgreSQL.Expression.Window
4143 Squeal.PostgreSQL.List
4244 Squeal.PostgreSQL.Manipulation
squeal-postgresql/src/Squeal/PostgreSQL.hs+4
@@ -205,9 +205,11 @@ module Squeal.PostgreSQL
205205 , module Squeal.PostgreSQL.Expression.Logic
206206 , module Squeal.PostgreSQL.Expression.Math
207207 , module Squeal.PostgreSQL.Expression.Null
208+ , module Squeal.PostgreSQL.Expression.Parameter
208209 , module Squeal.PostgreSQL.Expression.Text
209210 , module Squeal.PostgreSQL.Expression.TextSearch
210211 , module Squeal.PostgreSQL.Expression.Time
212+ , module Squeal.PostgreSQL.Expression.Type
211213 , module Squeal.PostgreSQL.Expression.Window
212214 , module Squeal.PostgreSQL.List
213215 , module Squeal.PostgreSQL.Manipulation
@@ -229,9 +231,11 @@ import Squeal.PostgreSQL.Expression.Json
229231import Squeal.PostgreSQL.Expression.Logic
230232import Squeal.PostgreSQL.Expression.Math
231233import Squeal.PostgreSQL.Expression.Null
234+import Squeal.PostgreSQL.Expression.Parameter
232235import Squeal.PostgreSQL.Expression.Text
233236import Squeal.PostgreSQL.Expression.TextSearch
234237import Squeal.PostgreSQL.Expression.Time
238+import Squeal.PostgreSQL.Expression.Type
235239import Squeal.PostgreSQL.Expression.Window
236240import Squeal.PostgreSQL.List
237241import Squeal.PostgreSQL.Manipulation
squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+1
@@ -98,6 +98,7 @@ import qualified GHC.Generics as GHC
9898import Squeal.PostgreSQL.Alias
9999import Squeal.PostgreSQL.Expression
100100import Squeal.PostgreSQL.Expression.Logic
101+import Squeal.PostgreSQL.Expression.Type
101102import Squeal.PostgreSQL.List
102103import Squeal.PostgreSQL.PG
103104import Squeal.PostgreSQL.Query
squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+4−287
@@ -46,50 +46,7 @@ module Squeal.PostgreSQL.Expression
4646 , FunctionN
4747 , unsafeFunctionN
4848 , Literal (..)
49− , HasParameter (parameter)
50− , param
5149 , PGSubset (..)
52− -- * Types
53− , TypeExpression (..)
54− , cast
55− , PGTyped (..)
56− , typedef
57− , typetable
58− , typeview
59− , bool
60− , int2
61− , smallint
62− , int4
63− , int
64− , integer
65− , int8
66− , bigint
67− , numeric
68− , float4
69− , real
70− , float8
71− , doublePrecision
72− , money
73− , text
74− , char
75− , character
76− , varchar
77− , characterVarying
78− , bytea
79− , timestamp
80− , timestampWithTimeZone
81− , date
82− , time
83− , timeWithTimeZone
84− , interval
85− , uuid
86− , inet
87− , json
88− , jsonb
89− , vararray
90− , fixarray
91− , tsvector
92− , tsquery
9350 -- * Re-export
9451 , (&)
9552 , K (..)
@@ -112,12 +69,10 @@ import GHC.TypeLits
11269import Numeric
11370import Prelude hiding (id, (.))
11471
115−import qualified Data.ByteString as ByteString
11672import qualified Data.Text as Text
11773import qualified Data.Text.Lazy as Lazy (Text)
11874import qualified Data.Text.Lazy as Lazy.Text
11975import qualified GHC.Generics as GHC
120−import qualified Generics.SOP as SOP
12176
12277import Squeal.PostgreSQL.Alias
12378import Squeal.PostgreSQL.Binary
@@ -236,46 +191,6 @@ unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y
236191unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized
237192 (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x)
238193
239−{- | A `HasParameter` constraint is used to indicate a value that is
240−supplied externally to a SQL statement.
241−`Squeal.PostgreSQL.PQ.manipulateParams`,
242−`Squeal.PostgreSQL.PQ.queryParams` and
243−`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
244−separately from the SQL command string, in which case `param`s are used to
245−refer to the out-of-line data values.
246−-}
247−class KnownNat n => HasParameter
248− (n :: Nat)
249− (params :: [NullityType])
250− (ty :: NullityType)
251− | n params -> ty where
252− -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
253− --
254− -- >>> let expr = parameter @1 int4 :: Expression outer '[] grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
255− -- >>> printSQL expr
256− -- ($1 :: int4)
257− parameter
258− :: TypeExpression schemas ty
259− -> Expression outer commons grp schemas params from ty
260− parameter ty = UnsafeExpression $ parenthesized $
261− "$" <> renderNat @n <+> "::"
262− <+> renderSQL ty
263−instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
264−instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
265− => HasParameter n (ty' : params) ty
266−
267−-- | `param` takes a `Nat` using type application and for basic types,
268−-- infers a `TypeExpression`.
269−--
270−-- >>> let expr = param @1 :: Expression outer commons grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
271−-- >>> printSQL expr
272−-- ($1 :: int4)
273−param
274− :: forall n outer commons schemas params from grp ty
275− . (PGTyped schemas ty, HasParameter n params ty)
276− => Expression outer commons grp schemas params from ty -- ^ param
277−param = parameter @n (pgtype @schemas)
278−
279194instance (HasUnique tab (Join outer from) row, Has col row ty)
280195 => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where
281196 fromLabel = UnsafeExpression $ renderSQL (Alias @col)
@@ -457,36 +372,17 @@ instance PGSubset 'PGjsonb
457372instance PGSubset 'PGtsquery
458373instance PGSubset ('PGvararray ty)
459374
460−-- When a `cast` is applied to an `Expression` of a known type, it
461−-- represents a run-time type conversion. The cast will succeed only if a
462−-- suitable type conversion operation has been defined.
463−--
464−-- | >>> printSQL $ true & cast int4
465−-- (TRUE :: int4)
466−cast
467− :: TypeExpression schemas ty1
468− -- ^ type to cast as
469− -> Expression outer commons grp schemas params from ty0
470− -- ^ value to convert
471− -> Expression outer commons grp schemas params from ty1
472−cast ty x = UnsafeExpression $ parenthesized $
473− renderSQL x <+> "::" <+> renderSQL ty
474−
475−{-----------------------------------------
476−text
477−-----------------------------------------}
478−
479375instance IsString
480376 (Expression outer commons grp schemas params from (null 'PGtext)) where
481377 fromString str = UnsafeExpression $
482378 "E\'" <> fromString (escape =<< str) <> "\'"
483379instance IsString
484380 (Expression outer commons grp schemas params from (null 'PGtsvector)) where
485− fromString str = cast tsvector . UnsafeExpression $
381+ fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $
486382 "E\'" <> fromString (escape =<< str) <> "\'"
487383instance IsString
488384 (Expression outer commons grp schemas params from (null 'PGtsquery)) where
489− fromString str = cast tsquery . UnsafeExpression $
385+ fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $
490386 "E\'" <> fromString (escape =<< str) <> "\'"
491387
492388instance Semigroup
@@ -511,192 +407,13 @@ instance Monoid
511407 mempty = fromString ""
512408 mappend = (<>)
513409
514−{-----------------------------------------
515−type expressions
516−-----------------------------------------}
517−
518−-- | `TypeExpression`s are used in `cast`s and
519−-- `Squeal.PostgreSQL.Definition.createTable` commands.
520−newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
521− = UnsafeTypeExpression { renderTypeExpression :: ByteString }
522− deriving (GHC.Generic,Show,Eq,Ord,NFData)
523−instance RenderSQL (TypeExpression schemas ty) where
524− renderSQL = renderTypeExpression
525−
526−-- | The enum or composite type in a `Typedef` can be expressed by its alias.
527−typedef
528− :: (Has sch schemas schema, Has td schema ('Typedef ty))
529− => QualifiedAlias sch td
530− -> TypeExpression schemas (null ty)
531−typedef = UnsafeTypeExpression . renderSQL
532−
533−-- | The composite type corresponding to a `Table` definition can be expressed
534−-- by its alias.
535−typetable
536− :: (Has sch schemas schema, Has tab schema ('Table table))
537− => QualifiedAlias sch tab
538− -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
539−typetable = UnsafeTypeExpression . renderSQL
540−
541−-- | The composite type corresponding to a `View` definition can be expressed
542−-- by its alias.
543−typeview
544− :: (Has sch schemas schema, Has vw schema ('View view))
545− => QualifiedAlias sch vw
546− -> TypeExpression schemas (null ('PGcomposite view))
547−typeview = UnsafeTypeExpression . renderSQL
548−
549−-- | logical Boolean (true/false)
550−bool :: TypeExpression schemas (null 'PGbool)
551−bool = UnsafeTypeExpression "bool"
552−-- | signed two-byte integer
553−int2, smallint :: TypeExpression schemas (null 'PGint2)
554−int2 = UnsafeTypeExpression "int2"
555−smallint = UnsafeTypeExpression "smallint"
556−-- | signed four-byte integer
557−int4, int, integer :: TypeExpression schemas (null 'PGint4)
558−int4 = UnsafeTypeExpression "int4"
559−int = UnsafeTypeExpression "int"
560−integer = UnsafeTypeExpression "integer"
561−-- | signed eight-byte integer
562−int8, bigint :: TypeExpression schemas (null 'PGint8)
563−int8 = UnsafeTypeExpression "int8"
564−bigint = UnsafeTypeExpression "bigint"
565−-- | arbitrary precision numeric type
566−numeric :: TypeExpression schemas (null 'PGnumeric)
567−numeric = UnsafeTypeExpression "numeric"
568−-- | single precision floating-point number (4 bytes)
569−float4, real :: TypeExpression schemas (null 'PGfloat4)
570−float4 = UnsafeTypeExpression "float4"
571−real = UnsafeTypeExpression "real"
572−-- | double precision floating-point number (8 bytes)
573−float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
574−float8 = UnsafeTypeExpression "float8"
575−doublePrecision = UnsafeTypeExpression "double precision"
576−-- | currency amount
577−money :: TypeExpression schema (null 'PGmoney)
578−money = UnsafeTypeExpression "money"
579−-- | variable-length character string
580−text :: TypeExpression schemas (null 'PGtext)
581−text = UnsafeTypeExpression "text"
582−-- | fixed-length character string
583−char, character
584− :: forall n schemas null. (KnownNat n, 1 <= n)
585− => TypeExpression schemas (null ('PGchar n))
586−char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
587−character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
588−-- | variable-length character string
589−varchar, characterVarying
590− :: forall n schemas null. (KnownNat n, 1 <= n)
591− => TypeExpression schemas (null ('PGvarchar n))
592−varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
593−characterVarying = UnsafeTypeExpression $
594− "character varying(" <> renderNat @n <> ")"
595−-- | binary data ("byte array")
596−bytea :: TypeExpression schemas (null 'PGbytea)
597−bytea = UnsafeTypeExpression "bytea"
598−-- | date and time (no time zone)
599−timestamp :: TypeExpression schemas (null 'PGtimestamp)
600−timestamp = UnsafeTypeExpression "timestamp"
601−-- | date and time, including time zone
602−timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
603−timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
604−-- | calendar date (year, month, day)
605−date :: TypeExpression schemas (null 'PGdate)
606−date = UnsafeTypeExpression "date"
607−-- | time of day (no time zone)
608−time :: TypeExpression schemas (null 'PGtime)
609−time = UnsafeTypeExpression "time"
610−-- | time of day, including time zone
611−timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
612−timeWithTimeZone = UnsafeTypeExpression "time with time zone"
613−-- | time span
614−interval :: TypeExpression schemas (null 'PGinterval)
615−interval = UnsafeTypeExpression "interval"
616−-- | universally unique identifier
617−uuid :: TypeExpression schemas (null 'PGuuid)
618−uuid = UnsafeTypeExpression "uuid"
619−-- | IPv4 or IPv6 host address
620−inet :: TypeExpression schemas (null 'PGinet)
621−inet = UnsafeTypeExpression "inet"
622−-- | textual JSON data
623−json :: TypeExpression schemas (null 'PGjson)
624−json = UnsafeTypeExpression "json"
625−-- | binary JSON data, decomposed
626−jsonb :: TypeExpression schemas (null 'PGjsonb)
627−jsonb = UnsafeTypeExpression "jsonb"
628−-- | variable length array
629−vararray
630− :: TypeExpression schemas pg
631− -> TypeExpression schemas (null ('PGvararray pg))
632−vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
633−-- | fixed length array
634−--
635−-- >>> renderSQL (fixarray @'[2] json)
636−-- "json[2]"
637−fixarray
638− :: forall dims schemas null pg. SOP.All KnownNat dims
639− => TypeExpression schemas pg
640− -> TypeExpression schemas (null ('PGfixarray dims pg))
641−fixarray ty = UnsafeTypeExpression $
642− renderSQL ty <> renderDims @dims
643− where
644− renderDims :: forall ns. SOP.All KnownNat ns => ByteString
645− renderDims =
646− ("[" <>)
647− . (<> "]")
648− . ByteString.intercalate "]["
649− . hcollapse
650− $ hcmap (SOP.Proxy @KnownNat)
651− (K . fromString . show . natVal)
652− (hpure SOP.Proxy :: NP SOP.Proxy ns)
653−tsvector :: TypeExpression schemas (null 'PGtsvector)
654−tsvector = UnsafeTypeExpression "tsvector"
655−tsquery :: TypeExpression schemas (null 'PGtsquery)
656−tsquery = UnsafeTypeExpression "tsquery"
657−
658−-- | `pgtype` is a demoted version of a `PGType`
659−class PGTyped schemas (ty :: NullityType) where
660− pgtype :: TypeExpression schemas ty
661−instance PGTyped schemas (null 'PGbool) where pgtype = bool
662−instance PGTyped schemas (null 'PGint2) where pgtype = int2
663−instance PGTyped schemas (null 'PGint4) where pgtype = int4
664−instance PGTyped schemas (null 'PGint8) where pgtype = int8
665−instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
666−instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
667−instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
668−instance PGTyped schemas (null 'PGmoney) where pgtype = money
669−instance PGTyped schemas (null 'PGtext) where pgtype = text
670−instance (KnownNat n, 1 <= n)
671− => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
672−instance (KnownNat n, 1 <= n)
673− => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
674−instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
675−instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
676−instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
677−instance PGTyped schemas (null 'PGdate) where pgtype = date
678−instance PGTyped schemas (null 'PGtime) where pgtype = time
679−instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
680−instance PGTyped schemas (null 'PGinterval) where pgtype = interval
681−instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
682−instance PGTyped schemas (null 'PGjson) where pgtype = json
683−instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
684−instance PGTyped schemas ty
685− => PGTyped schemas (null ('PGvararray ty)) where
686− pgtype = vararray (pgtype @schemas @ty)
687−instance (SOP.All KnownNat dims, PGTyped schemas ty)
688− => PGTyped schemas (null ('PGfixarray dims ty)) where
689− pgtype = fixarray @dims (pgtype @schemas @ty)
690−instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
691−instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
692−
693410class Literal hask where
694411 literal :: hask -> Expr (null (PG hask))
695412instance JSON.ToJSON hask => Literal (Json hask) where
696− literal = cast json . UnsafeExpression
413+ literal = UnsafeExpression . parenthesized . (<> " :: json")
697414 . singleQuotedUtf8 . toStrict . JSON.encode . getJson
698415instance JSON.ToJSON hask => Literal (Jsonb hask) where
699− literal = cast jsonb . UnsafeExpression
416+ literal = UnsafeExpression . parenthesized . (<> " :: jsonb")
700417 . singleQuotedUtf8 . toStrict . JSON.encode . getJsonb
701418instance Literal Char where
702419 literal chr = UnsafeExpression $
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Parameter.hsnew file+70
@@ -0,0 +1,70 @@
1+{-# LANGUAGE
2+ AllowAmbiguousTypes
3+ , DataKinds
4+ , FlexibleContexts
5+ , FlexibleInstances
6+ , FunctionalDependencies
7+ , KindSignatures
8+ , MultiParamTypeClasses
9+ , OverloadedStrings
10+ , RankNTypes
11+ , ScopedTypeVariables
12+ , TypeApplications
13+ , TypeOperators
14+ , UndecidableInstances
15+#-}
16+
17+module Squeal.PostgreSQL.Expression.Parameter
18+ ( HasParameter (parameter)
19+ , param
20+ ) where
21+
22+import GHC.TypeLits
23+
24+import Squeal.PostgreSQL.Expression
25+import Squeal.PostgreSQL.Expression.Type
26+import Squeal.PostgreSQL.Render
27+import Squeal.PostgreSQL.Schema
28+
29+-- $setup
30+-- >>> import Squeal.PostgreSQL
31+
32+{- | A `HasParameter` constraint is used to indicate a value that is
33+supplied externally to a SQL statement.
34+`Squeal.PostgreSQL.PQ.manipulateParams`,
35+`Squeal.PostgreSQL.PQ.queryParams` and
36+`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values
37+separately from the SQL command string, in which case `param`s are used to
38+refer to the out-of-line data values.
39+-}
40+class KnownNat n => HasParameter
41+ (n :: Nat)
42+ (params :: [NullityType])
43+ (ty :: NullityType)
44+ | n params -> ty where
45+ -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.
46+ --
47+ -- >>> let expr = parameter @1 int4 :: Expression outer '[] grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
48+ -- >>> printSQL expr
49+ -- ($1 :: int4)
50+ parameter
51+ :: TypeExpression schemas ty
52+ -> Expression outer commons grp schemas params from ty
53+ parameter ty = UnsafeExpression $ parenthesized $
54+ "$" <> renderNat @n <+> "::"
55+ <+> renderSQL ty
56+instance {-# OVERLAPPING #-} HasParameter 1 (ty1:tys) ty1
57+instance {-# OVERLAPPABLE #-} (KnownNat n, HasParameter (n-1) params ty)
58+ => HasParameter n (ty' : params) ty
59+
60+-- | `param` takes a `Nat` using type application and for basic types,
61+-- infers a `TypeExpression`.
62+--
63+-- >>> let expr = param @1 :: Expression outer commons grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
64+-- >>> printSQL expr
65+-- ($1 :: int4)
66+param
67+ :: forall n outer commons schemas params from grp ty
68+ . (PGTyped schemas ty, HasParameter n params ty)
69+ => Expression outer commons grp schemas params from ty -- ^ param
70+param = parameter @n (pgtype @schemas)
squeal-postgresql/src/Squeal/PostgreSQL/Expression/Type.hsnew file+271
@@ -0,0 +1,271 @@
1+{-# LANGUAGE
2+ AllowAmbiguousTypes
3+ , DataKinds
4+ , DeriveGeneric
5+ , FlexibleContexts
6+ , FlexibleInstances
7+ , GADTs
8+ , GeneralizedNewtypeDeriving
9+ , KindSignatures
10+ , MultiParamTypeClasses
11+ , OverloadedStrings
12+ , RankNTypes
13+ , ScopedTypeVariables
14+ , TypeApplications
15+ , TypeOperators
16+#-}
17+
18+module Squeal.PostgreSQL.Expression.Type
19+ ( TypeExpression (..)
20+ , cast
21+ , PGTyped (..)
22+ , typedef
23+ , typetable
24+ , typeview
25+ , bool
26+ , int2
27+ , smallint
28+ , int4
29+ , int
30+ , integer
31+ , int8
32+ , bigint
33+ , numeric
34+ , float4
35+ , real
36+ , float8
37+ , doublePrecision
38+ , money
39+ , text
40+ , char
41+ , character
42+ , varchar
43+ , characterVarying
44+ , bytea
45+ , timestamp
46+ , timestampWithTimeZone
47+ , date
48+ , time
49+ , timeWithTimeZone
50+ , interval
51+ , uuid
52+ , inet
53+ , json
54+ , jsonb
55+ , vararray
56+ , fixarray
57+ , tsvector
58+ , tsquery
59+ ) where
60+
61+import Control.DeepSeq
62+import Data.ByteString
63+import Data.String
64+import GHC.TypeLits
65+
66+import qualified Data.ByteString as ByteString
67+import qualified GHC.Generics as GHC
68+import qualified Generics.SOP as SOP
69+
70+import Squeal.PostgreSQL.Alias
71+import Squeal.PostgreSQL.Expression
72+import Squeal.PostgreSQL.Render
73+import Squeal.PostgreSQL.Schema
74+
75+-- $setup
76+-- >>> import Squeal.PostgreSQL
77+
78+-- When a `cast` is applied to an `Expression` of a known type, it
79+-- represents a run-time type conversion. The cast will succeed only if a
80+-- suitable type conversion operation has been defined.
81+--
82+-- | >>> printSQL $ true & cast int4
83+-- (TRUE :: int4)
84+cast
85+ :: TypeExpression schemas ty1
86+ -- ^ type to cast as
87+ -> Expression outer commons grp schemas params from ty0
88+ -- ^ value to convert
89+ -> Expression outer commons grp schemas params from ty1
90+cast ty x = UnsafeExpression $ parenthesized $
91+ renderSQL x <+> "::" <+> renderSQL ty
92+
93+
94+{-----------------------------------------
95+type expressions
96+-----------------------------------------}
97+
98+-- | `TypeExpression`s are used in `cast`s and
99+-- `Squeal.PostgreSQL.Definition.createTable` commands.
100+newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
101+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
102+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
103+instance RenderSQL (TypeExpression schemas ty) where
104+ renderSQL = renderTypeExpression
105+
106+-- | The enum or composite type in a `Typedef` can be expressed by its alias.
107+typedef
108+ :: (Has sch schemas schema, Has td schema ('Typedef ty))
109+ => QualifiedAlias sch td
110+ -> TypeExpression schemas (null ty)
111+typedef = UnsafeTypeExpression . renderSQL
112+
113+-- | The composite type corresponding to a `Table` definition can be expressed
114+-- by its alias.
115+typetable
116+ :: (Has sch schemas schema, Has tab schema ('Table table))
117+ => QualifiedAlias sch tab
118+ -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))
119+typetable = UnsafeTypeExpression . renderSQL
120+
121+-- | The composite type corresponding to a `View` definition can be expressed
122+-- by its alias.
123+typeview
124+ :: (Has sch schemas schema, Has vw schema ('View view))
125+ => QualifiedAlias sch vw
126+ -> TypeExpression schemas (null ('PGcomposite view))
127+typeview = UnsafeTypeExpression . renderSQL
128+
129+-- | logical Boolean (true/false)
130+bool :: TypeExpression schemas (null 'PGbool)
131+bool = UnsafeTypeExpression "bool"
132+-- | signed two-byte integer
133+int2, smallint :: TypeExpression schemas (null 'PGint2)
134+int2 = UnsafeTypeExpression "int2"
135+smallint = UnsafeTypeExpression "smallint"
136+-- | signed four-byte integer
137+int4, int, integer :: TypeExpression schemas (null 'PGint4)
138+int4 = UnsafeTypeExpression "int4"
139+int = UnsafeTypeExpression "int"
140+integer = UnsafeTypeExpression "integer"
141+-- | signed eight-byte integer
142+int8, bigint :: TypeExpression schemas (null 'PGint8)
143+int8 = UnsafeTypeExpression "int8"
144+bigint = UnsafeTypeExpression "bigint"
145+-- | arbitrary precision numeric type
146+numeric :: TypeExpression schemas (null 'PGnumeric)
147+numeric = UnsafeTypeExpression "numeric"
148+-- | single precision floating-point number (4 bytes)
149+float4, real :: TypeExpression schemas (null 'PGfloat4)
150+float4 = UnsafeTypeExpression "float4"
151+real = UnsafeTypeExpression "real"
152+-- | double precision floating-point number (8 bytes)
153+float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)
154+float8 = UnsafeTypeExpression "float8"
155+doublePrecision = UnsafeTypeExpression "double precision"
156+-- | currency amount
157+money :: TypeExpression schema (null 'PGmoney)
158+money = UnsafeTypeExpression "money"
159+-- | variable-length character string
160+text :: TypeExpression schemas (null 'PGtext)
161+text = UnsafeTypeExpression "text"
162+-- | fixed-length character string
163+char, character
164+ :: forall n schemas null. (KnownNat n, 1 <= n)
165+ => TypeExpression schemas (null ('PGchar n))
166+char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")"
167+character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")"
168+-- | variable-length character string
169+varchar, characterVarying
170+ :: forall n schemas null. (KnownNat n, 1 <= n)
171+ => TypeExpression schemas (null ('PGvarchar n))
172+varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")"
173+characterVarying = UnsafeTypeExpression $
174+ "character varying(" <> renderNat @n <> ")"
175+-- | binary data ("byte array")
176+bytea :: TypeExpression schemas (null 'PGbytea)
177+bytea = UnsafeTypeExpression "bytea"
178+-- | date and time (no time zone)
179+timestamp :: TypeExpression schemas (null 'PGtimestamp)
180+timestamp = UnsafeTypeExpression "timestamp"
181+-- | date and time, including time zone
182+timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
183+timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"
184+-- | calendar date (year, month, day)
185+date :: TypeExpression schemas (null 'PGdate)
186+date = UnsafeTypeExpression "date"
187+-- | time of day (no time zone)
188+time :: TypeExpression schemas (null 'PGtime)
189+time = UnsafeTypeExpression "time"
190+-- | time of day, including time zone
191+timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
192+timeWithTimeZone = UnsafeTypeExpression "time with time zone"
193+-- | time span
194+interval :: TypeExpression schemas (null 'PGinterval)
195+interval = UnsafeTypeExpression "interval"
196+-- | universally unique identifier
197+uuid :: TypeExpression schemas (null 'PGuuid)
198+uuid = UnsafeTypeExpression "uuid"
199+-- | IPv4 or IPv6 host address
200+inet :: TypeExpression schemas (null 'PGinet)
201+inet = UnsafeTypeExpression "inet"
202+-- | textual JSON data
203+json :: TypeExpression schemas (null 'PGjson)
204+json = UnsafeTypeExpression "json"
205+-- | binary JSON data, decomposed
206+jsonb :: TypeExpression schemas (null 'PGjsonb)
207+jsonb = UnsafeTypeExpression "jsonb"
208+-- | variable length array
209+vararray
210+ :: TypeExpression schemas pg
211+ -> TypeExpression schemas (null ('PGvararray pg))
212+vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]"
213+-- | fixed length array
214+--
215+-- >>> renderSQL (fixarray @'[2] json)
216+-- "json[2]"
217+fixarray
218+ :: forall dims schemas null pg. SOP.All KnownNat dims
219+ => TypeExpression schemas pg
220+ -> TypeExpression schemas (null ('PGfixarray dims pg))
221+fixarray ty = UnsafeTypeExpression $
222+ renderSQL ty <> renderDims @dims
223+ where
224+ renderDims :: forall ns. SOP.All KnownNat ns => ByteString
225+ renderDims =
226+ ("[" <>)
227+ . (<> "]")
228+ . ByteString.intercalate "]["
229+ . SOP.hcollapse
230+ $ SOP.hcmap (SOP.Proxy @KnownNat)
231+ (K . fromString . show . natVal)
232+ (SOP.hpure SOP.Proxy :: SOP.NP SOP.Proxy ns)
233+tsvector :: TypeExpression schemas (null 'PGtsvector)
234+tsvector = UnsafeTypeExpression "tsvector"
235+tsquery :: TypeExpression schemas (null 'PGtsquery)
236+tsquery = UnsafeTypeExpression "tsquery"
237+
238+-- | `pgtype` is a demoted version of a `PGType`
239+class PGTyped schemas (ty :: NullityType) where
240+ pgtype :: TypeExpression schemas ty
241+instance PGTyped schemas (null 'PGbool) where pgtype = bool
242+instance PGTyped schemas (null 'PGint2) where pgtype = int2
243+instance PGTyped schemas (null 'PGint4) where pgtype = int4
244+instance PGTyped schemas (null 'PGint8) where pgtype = int8
245+instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric
246+instance PGTyped schemas (null 'PGfloat4) where pgtype = float4
247+instance PGTyped schemas (null 'PGfloat8) where pgtype = float8
248+instance PGTyped schemas (null 'PGmoney) where pgtype = money
249+instance PGTyped schemas (null 'PGtext) where pgtype = text
250+instance (KnownNat n, 1 <= n)
251+ => PGTyped schemas (null ('PGchar n)) where pgtype = char @n
252+instance (KnownNat n, 1 <= n)
253+ => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n
254+instance PGTyped schemas (null 'PGbytea) where pgtype = bytea
255+instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp
256+instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone
257+instance PGTyped schemas (null 'PGdate) where pgtype = date
258+instance PGTyped schemas (null 'PGtime) where pgtype = time
259+instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone
260+instance PGTyped schemas (null 'PGinterval) where pgtype = interval
261+instance PGTyped schemas (null 'PGuuid) where pgtype = uuid
262+instance PGTyped schemas (null 'PGjson) where pgtype = json
263+instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb
264+instance PGTyped schemas ty
265+ => PGTyped schemas (null ('PGvararray ty)) where
266+ pgtype = vararray (pgtype @schemas @ty)
267+instance (SOP.All KnownNat dims, PGTyped schemas ty)
268+ => PGTyped schemas (null ('PGfixarray dims ty)) where
269+ pgtype = fixarray @dims (pgtype @schemas @ty)
270+instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector
271+instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery
squeal-postgresql/src/Squeal/PostgreSQL/Query.hs+1
@@ -116,6 +116,7 @@ import Squeal.PostgreSQL.Alias
116116import Squeal.PostgreSQL.Expression
117117import Squeal.PostgreSQL.Expression.Logic
118118import Squeal.PostgreSQL.Expression.Sort
119+import Squeal.PostgreSQL.Expression.Type
119120import Squeal.PostgreSQL.Expression.Window
120121import Squeal.PostgreSQL.List
121122import Squeal.PostgreSQL.PG