@@ -1,4 +1,13 @@
1−
1+{-|
2+Module: Squeal.PostgreSQL.PG
3+Description: Embedding of Haskell types into Postgres's type system
4+Copyright: (c) Eitan Chatav, 2010
5+Maintainer: eitan@morphism.tech
6+Stability: experimental
7+
8+`Squeal.PostgreSQL.PG` provides type families for turning Haskell
9+`Type`s into corresponding Postgres types.
10+-}
211{-# LANGUAGE
312 AllowAmbiguousTypes
413 , DeriveFoldable
@@ -28,7 +37,6 @@ module Squeal.PostgreSQL.PG
2837 , NullPG
2938 , TuplePG
3039 , RowPG
31− , Entity
3240 -- * Storage newtypes
3341 , Money (..)
3442 , Json (..)
@@ -45,7 +53,6 @@ module Squeal.PostgreSQL.PG
4553 , TupleOf
4654 , TupleCodeOf
4755 , RowOf
48− , ColumnsOf
4956 , ConstructorsOf
5057 , ConstructorNameOf
5158 , ConstructorNamesOf
@@ -91,30 +98,55 @@ PG LocalTime :: PGType
9198>>> type instance PG MyDouble = 'PGfloat8
9299-}
93100type family PG (hask :: Type) :: PGType
101+-- | `PGbool`
94102type instance PG Bool = 'PGbool
103+-- | `PGint2`
95104type instance PG Int16 = 'PGint2
105+-- | `PGint4`
96106type instance PG Int32 = 'PGint4
107+-- | `PGint8`
97108type instance PG Int64 = 'PGint8
109+-- | `PGint2`
98110type instance PG Word16 = 'PGint2
111+-- | `PGint4`
99112type instance PG Word32 = 'PGint4
113+-- | `PGint8`
100114type instance PG Word64 = 'PGint8
115+-- | `PGnumeric`
101116type instance PG Scientific = 'PGnumeric
117+-- | `PGfloat4`
102118type instance PG Float = 'PGfloat4
119+-- | `PGfloat8`
103120type instance PG Double = 'PGfloat8
121+-- | `PGchar` @1@
104122type instance PG Char = 'PGchar 1
123+-- | `PGtext`
105124type instance PG Strict.Text = 'PGtext
125+-- | `PGtext`
106126type instance PG Lazy.Text = 'PGtext
127+-- | `PGtext`
107128type instance PG String = 'PGtext
129+-- | `PGbytea`
108130type instance PG Strict.ByteString = 'PGbytea
131+-- | `PGbytea`
109132type instance PG Lazy.ByteString = 'PGbytea
133+-- | `PGtimestamp`
110134type instance PG LocalTime = 'PGtimestamp
135+-- | `PGtimestamptz`
111136type instance PG UTCTime = 'PGtimestamptz
137+-- | `PGdate`
112138type instance PG Day = 'PGdate
139+-- | `PGtime`
113140type instance PG TimeOfDay = 'PGtime
141+-- | `PGtimetz`
114142type instance PG (TimeOfDay, TimeZone) = 'PGtimetz
143+-- | `PGinterval`
115144type instance PG DiffTime = 'PGinterval
145+-- | `PGuuid`
116146type instance PG UUID = 'PGuuid
147+-- | `PGinet`
117148type instance PG (NetAddr IP) = 'PGinet
149+-- | `PGjson`
118150type instance PG Value = 'PGjson
119151
120152{-| The `LabelsPG` type family calculates the constructors of a
@@ -170,58 +202,11 @@ type family RowPG (hask :: Type) :: RowType where
170202 RowPG (SOP.P (col ::: ty)) = '[col ::: NullPG ty]
171203 RowPG hask = RowOf (SOP.RecordCodeOf hask)
172204
205+-- | `RowOf` applies `NullPG` to the fields of a list.
173206type family RowOf (record :: [(Symbol, Type)]) :: RowType where
174207 RowOf '[] = '[]
175208 RowOf (col ::: ty ': record) = col ::: NullPG ty ': RowOf record
176209
177−type family ColumnsOf (record :: [(Symbol, Type)]) :: ColumnsType where
178− ColumnsOf '[] = '[]
179− ColumnsOf (col ::: ty ': record) =
180− col ::: 'NoDef :=> NullPG ty ': ColumnsOf record
181−
182−{- |
183−`Entity` turns a Haskell `Type` into a `ColumnsType`.
184−
185−`Entity` may be applied to normal Haskell record types provided they
186−have the `SOP.Generic` and `SOP.HasDatatypeInfo` instances;
187−
188−>>> data Person = Person { name :: Strict.Text, age :: Int32 } deriving GHC.Generic
189−>>> instance SOP.Generic Person
190−>>> instance SOP.HasDatatypeInfo Person
191−>>> :kind! Entity Person
192−Entity Person :: [(Symbol, (ColumnConstraint, NullityType))]
193−= '["name" ::: ('NoDef :=> 'NotNull 'PGtext),
194− "age" ::: ('NoDef :=> 'NotNull 'PGint4)]
195−
196−Or to tuples of `SOP.P` types;
197−
198−>>> :kind! Entity (SOP.P ("id" ::: Int32), SOP.P ("foreign_id" ::: Int32))
199−Entity (SOP.P ("id" ::: Int32), SOP.P ("foreign_id" ::: Int32)) :: [(Symbol,
200− ColumnType)]
201−= '[ '("id", 'Def :=> 'NotNull 'PGint4),
202− "foreign_id" ::: ('Def :=> 'NotNull 'PGint4)]
203−
204−Or to tuples which mix `SOP.P` types and record types.
205−
206−>>> :kind! Entity (SOP.P ("id" ::: Int32), Person, SOP.P ("foreign_id" ::: Int32))
207−Entity (SOP.P ("id" ::: Int32), Person, SOP.P ("foreign_id" ::: Int32)) :: [(Symbol,
208− ColumnType)]
209−= '[ '("id", 'Def :=> 'NotNull 'PGint4),
210− '("name", 'NoDef :=> 'NotNull 'PGtext),
211− '("age", 'NoDef :=> 'NotNull 'PGint4),
212− "foreign_id" ::: ('Def :=> 'NotNull 'PGint4)]
213−-}
214−type family Entity (hask :: Type) :: ColumnsType where
215− Entity (hask1, hask2) = Join (Entity hask1) (Entity hask2)
216− Entity (hask1, hask2, hask3) =
217− Join (Entity hask1) (Entity (hask2, hask3))
218− Entity (hask1, hask2, hask3, hask4) =
219− Join (Entity hask1) (Entity (hask2, hask3, hask4))
220− Entity (hask1, hask2, hask3, hask4, hask5) =
221− Join (Entity hask1) (Entity (hask2, hask3, hask4, hask5))
222− Entity (SOP.P (col ::: ty)) = '[col ::: 'Def :=> NullPG ty]
223− Entity hask = ColumnsOf (SOP.RecordCodeOf hask)
224−
225210{- | `NullPG` turns a Haskell type into a `NullityType`.
226211
227212>>> :kind! NullPG Double
@@ -245,10 +230,13 @@ TuplePG (Double, Maybe Char) :: [NullityType]
245230type family TuplePG (hask :: Type) :: [NullityType] where
246231 TuplePG hask = TupleOf (TupleCodeOf hask (SOP.Code hask))
247232
233+-- | `TupleOf` turns a list of Haskell `Type`s into a list of `NullityType`s.
248234type family TupleOf (tuple :: [Type]) :: [NullityType] where
249235 TupleOf '[] = '[]
250236 TupleOf (hask ': tuple) = NullPG hask ': TupleOf tuple
251237
238+-- | `TupleCodeOf` takes the `SOP.Code` of a haskell `Type`
239+-- and if it's a simple product returns it, otherwise giving a `TypeError`.
252240type family TupleCodeOf (hask :: Type) (code :: [[Type]]) :: [Type] where
253241 TupleCodeOf hask '[tuple] = tuple
254242 TupleCodeOf hask '[] =
@@ -289,6 +277,7 @@ type family ConstructorNamesOf (constructors :: [Type.ConstructorInfo])
289277 ConstructorNamesOf (constructor ': constructors) =
290278 ConstructorNameOf constructor ': ConstructorNamesOf constructors
291279
280+-- | `DimPG` turns Haskell nested homogeneous tuples into a list of lengths.
292281type family DimPG (hask :: Type) :: [Nat] where
293282 DimPG (x,x) = 2 ': DimPG x
294283 DimPG (x,x,x) = 3 ': DimPG x
@@ -301,6 +290,7 @@ type family DimPG (hask :: Type) :: [Nat] where
301290 DimPG (x,x,x,x,x,x,x,x,x,x) = 10 ': DimPG x
302291 DimPG x = '[]
303292
293+-- | `FixPG` extracts `NullPG` of the base type of nested homogeneous tuples.
304294type family FixPG (hask :: Type) :: NullityType where
305295 FixPG (x,x) = FixPG x
306296 FixPG (x,x,x) = FixPG x
@@ -339,6 +329,7 @@ True
339329-}
340330newtype Money = Money { cents :: Int64 }
341331 deriving (Eq, Ord, Show, Read, GHC.Generic)
332+-- | `PGmoney`
342333type instance PG Money = 'PGmoney
343334
344335{- | The `Json` newtype is an indication that the Haskell
@@ -346,6 +337,7 @@ type it's applied to should be stored as a `PGjson`.
346337-}
347338newtype Json hask = Json {getJson :: hask}
348339 deriving (Eq, Ord, Show, Read, GHC.Generic)
340+-- | `PGjson`
349341type instance PG (Json hask) = 'PGjson
350342
351343{- | The `Jsonb` newtype is an indication that the Haskell
@@ -353,6 +345,7 @@ type it's applied to should be stored as a `PGjsonb`.
353345-}
354346newtype Jsonb hask = Jsonb {getJsonb :: hask}
355347 deriving (Eq, Ord, Show, Read, GHC.Generic)
348+-- | `PGjsonb`
356349type instance PG (Jsonb hask) = 'PGjsonb
357350
358351{- | The `Composite` newtype is an indication that the Haskell
@@ -360,6 +353,7 @@ type it's applied to should be stored as a `PGcomposite`.
360353-}
361354newtype Composite record = Composite {getComposite :: record}
362355 deriving (Eq, Ord, Show, Read, GHC.Generic)
356+-- | `PGcomposite` @(@`RowPG` @hask)@
363357type instance PG (Composite hask) = 'PGcomposite (RowPG hask)
364358
365359{- | The `Enumerated` newtype is an indication that the Haskell
@@ -367,6 +361,7 @@ type it's applied to should be stored as a `PGenum`.
367361-}
368362newtype Enumerated enum = Enumerated {getEnumerated :: enum}
369363 deriving (Eq, Ord, Show, Read, GHC.Generic)
364+-- | `PGenum` @(@`LabelsPG` @hask)@
370365type instance PG (Enumerated hask) = 'PGenum (LabelsPG hask)
371366
372367{- | The `VarArray` newtype is an indication that the Haskell
@@ -374,6 +369,7 @@ type it's applied to should be stored as a `PGvararray`.
374369-}
375370newtype VarArray arr = VarArray {getVarArray :: arr}
376371 deriving (Eq, Ord, Show, Read, GHC.Generic)
372+-- | `PGvararray` @(@`NullPG` @hask)@
377373type instance PG (VarArray (Vector hask)) = 'PGvararray (NullPG hask)
378374
379375{- | The `FixArray` newtype is an indication that the Haskell
@@ -381,4 +377,5 @@ type it's applied to should be stored as a `PGfixarray`.
381377-}
382378newtype FixArray arr = FixArray {getFixArray :: arr}
383379 deriving (Eq, Ord, Show, Read, GHC.Generic)
384−type instance PG (FixArray x) = 'PGfixarray (DimPG x) (FixPG x)
380+-- | `PGfixarray` @(@`DimPG` @hask) (@`FixPG` @hask)@
381+type instance PG (FixArray hask) = 'PGfixarray (DimPG hask) (FixPG hask)