@@ -97,7 +97,7 @@ let
9797CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');
9898```
9999
100−Enumerated types can also be generated from a Haskell algbraic data type with nullary constructors, for example
100+Enumerated types can also be generated from a Haskell algbraic data type with nullary constructors, for example:
101101
102102```Haskell
103103>>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
@@ -132,8 +132,37 @@ in printSQL expression
132132
133133**Composite Types**
134134
135+In addition to enum types, you can define composite types.
136+A composite type represents the structure of a row or record;
137+it is essentially just a list of field names and their data types.
135138
136139
140+`createTypeComposite` creates a composite type. The composite type is
141+specified by a list of attribute names and data types.
142+
143+```Haskell
144+>>> :{
145+let
146+ definition :: Definition '[] '["complex" ::: 'Typedef ('PGcomposite '["real" ::: 'PGfloat8, "imaginary" ::: 'PGfloat8])]
147+ definition = createTypeComposite #complex (float8 `As` #real :* float8 `As` #imaginary :* Nil)
148+:}
149+>>> printSQL definition
150+CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
151+```
152+
153+Composite types are almost equivalent to Haskell record types.
154+However, because of the potential presence of @NULL@
155+all the record fields must be `Maybe`s of basic types.
156+Composite types can be generated from a Haskell record type, for example:
157+
158+```Haskell
159+>>> data Complex = Complex {real :: Maybe Double, imaginary :: Maybe Double} deriving GHC.Generic
160+>>> instance SOP.Generic Complex
161+>>> instance SOP.HasDatatypeInfo Complex
162+>>> printSQL $ createTypeCompositeFrom @Complex #complex
163+CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
164+```
165+
137166### Version 0.2.1 - April 7, 2018
138167
139168This minor update fixes an issue where alias identifiers could conflict with