squeal-postgresql 0.5.2.0 → 0.6.0.0
raw patch · 85 files changed
+11898/−6994 lines, 85 filesdep +QuickCheckdep +binarydep +free-categoriesdep ~basedep ~generics-sopdep ~mtlnew-component:exe:examplePVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, binary, free-categories, gauge, generic-random, hedgehog, monad-loops, profunctors, quickcheck-instances, with-utf8
Dependency ranges changed: base, generics-sop, mtl, text
API changes (from Hackage documentation)
- Squeal.PostgreSQL.Alias: (!) :: IsQualified table column expression => Alias table -> Alias column -> expression
- Squeal.PostgreSQL.Alias: Alias :: Alias
- Squeal.PostgreSQL.Alias: Grouped :: [(Symbol, Symbol)] -> Grouping
- Squeal.PostgreSQL.Alias: QualifiedAlias :: QualifiedAlias
- Squeal.PostgreSQL.Alias: Ungrouped :: Grouping
- Squeal.PostgreSQL.Alias: [As] :: KnownSymbol alias => expression ty -> Alias alias -> Aliased expression (alias ::: ty)
- Squeal.PostgreSQL.Alias: as :: Aliasable alias expression aliased => expression -> Alias alias -> aliased
- Squeal.PostgreSQL.Alias: class KnownSymbol alias => Aliasable alias expression aliased | aliased -> expression, aliased -> alias
- Squeal.PostgreSQL.Alias: class (KnownSymbol table, KnownSymbol column) => GroupedBy table column bys
- Squeal.PostgreSQL.Alias: class KnownSymbol alias => Has (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) | alias fields -> field
- Squeal.PostgreSQL.Alias: class (All KnownSymbol aliases) => HasAll (aliases :: [Symbol]) (fields :: [(Symbol, kind)]) (subfields :: [(Symbol, kind)]) | aliases fields -> subfields
- Squeal.PostgreSQL.Alias: class HasIn fields field
- Squeal.PostgreSQL.Alias: class IsLabel (x :: Symbol) a
- Squeal.PostgreSQL.Alias: class IsQualified table column expression
- Squeal.PostgreSQL.Alias: data Alias (alias :: Symbol)
- Squeal.PostgreSQL.Alias: data Aliased expression aliased
- Squeal.PostgreSQL.Alias: data Grouping
- Squeal.PostgreSQL.Alias: data QualifiedAlias (qualifier :: Symbol) (alias :: Symbol)
- Squeal.PostgreSQL.Alias: fromLabel :: IsLabel x a => a
- Squeal.PostgreSQL.Alias: infixl 9 !
- Squeal.PostgreSQL.Alias: infixr 6 :::
- Squeal.PostgreSQL.Alias: instance (GHC.TypeLits.KnownSymbol q, GHC.TypeLits.KnownSymbol a) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Alias.QualifiedAlias q a)
- Squeal.PostgreSQL.Alias: instance (GHC.TypeLits.KnownSymbol table, GHC.TypeLits.KnownSymbol column) => Squeal.PostgreSQL.Alias.GroupedBy table column ('(table, column) : bys)
- Squeal.PostgreSQL.Alias: instance (alias0 Data.Type.Equality.~ alias1, alias0 Data.Type.Equality.~ alias2, GHC.TypeLits.KnownSymbol alias2) => GHC.OverloadedLabels.IsLabel alias0 (Squeal.PostgreSQL.Alias.Aliased Squeal.PostgreSQL.Alias.Alias (alias1 Squeal.PostgreSQL.Alias.::: alias2))
- Squeal.PostgreSQL.Alias: instance (alias1 Data.Type.Equality.~ alias2) => GHC.OverloadedLabels.IsLabel alias1 (Squeal.PostgreSQL.Alias.Alias alias2)
- Squeal.PostgreSQL.Alias: instance (aliases Data.Type.Equality.~ '[alias]) => GHC.OverloadedLabels.IsLabel alias (Data.SOP.NP.NP Squeal.PostgreSQL.Alias.Alias aliases)
- Squeal.PostgreSQL.Alias: instance (q Data.Type.Equality.~ "public", a0 Data.Type.Equality.~ a1, a1 Data.Type.Equality.~ a2, GHC.TypeLits.KnownSymbol a2) => GHC.OverloadedLabels.IsLabel a0 (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Alias.QualifiedAlias q) (a1 Squeal.PostgreSQL.Alias.::: a2))
- Squeal.PostgreSQL.Alias: instance (q Data.Type.Equality.~ q', a Data.Type.Equality.~ a') => Squeal.PostgreSQL.Alias.IsQualified q a (Squeal.PostgreSQL.Alias.QualifiedAlias q' a')
- Squeal.PostgreSQL.Alias: instance (q' Data.Type.Equality.~ "public", a Data.Type.Equality.~ a') => GHC.OverloadedLabels.IsLabel a (Squeal.PostgreSQL.Alias.QualifiedAlias q' a')
- Squeal.PostgreSQL.Alias: instance (q0 Data.Type.Equality.~ q1, a0 Data.Type.Equality.~ a1, a1 Data.Type.Equality.~ a2, GHC.TypeLits.KnownSymbol a2) => Squeal.PostgreSQL.Alias.IsQualified q0 a0 (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Alias.QualifiedAlias q1) (a1 Squeal.PostgreSQL.Alias.::: a2))
- Squeal.PostgreSQL.Alias: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Alias.Alias alias)
- Squeal.PostgreSQL.Alias: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
- Squeal.PostgreSQL.Alias: instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol aliases => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Alias.Alias aliases)
- Squeal.PostgreSQL.Alias: instance GHC.Classes.Eq (Squeal.PostgreSQL.Alias.Alias alias)
- Squeal.PostgreSQL.Alias: instance GHC.Classes.Eq (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
- Squeal.PostgreSQL.Alias: instance GHC.Classes.Ord (Squeal.PostgreSQL.Alias.Alias alias)
- Squeal.PostgreSQL.Alias: instance GHC.Classes.Ord (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
- Squeal.PostgreSQL.Alias: instance GHC.Generics.Generic (Squeal.PostgreSQL.Alias.Alias alias)
- Squeal.PostgreSQL.Alias: instance GHC.Generics.Generic (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
- Squeal.PostgreSQL.Alias: instance GHC.Show.Show (Squeal.PostgreSQL.Alias.Alias alias)
- Squeal.PostgreSQL.Alias: instance GHC.Show.Show (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
- Squeal.PostgreSQL.Alias: instance GHC.TypeLits.KnownSymbol alias => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Alias.Alias alias)
- Squeal.PostgreSQL.Alias: instance Squeal.PostgreSQL.Alias.IsQualified table column (Squeal.PostgreSQL.Alias.Alias table, Squeal.PostgreSQL.Alias.Alias column)
- Squeal.PostgreSQL.Alias: instance forall a (table :: GHC.Types.Symbol) (column :: GHC.Types.Symbol) (bys :: [a]) (tabcol :: a). (GHC.TypeLits.KnownSymbol table, GHC.TypeLits.KnownSymbol column, Squeal.PostgreSQL.Alias.GroupedBy table column bys) => Squeal.PostgreSQL.Alias.GroupedBy table column (tabcol : bys)
- Squeal.PostgreSQL.Alias: instance forall k (alias :: GHC.Types.Symbol) (aliased :: (GHC.Types.Symbol, k)) (ty :: k) (expression :: k -> *). (GHC.TypeLits.KnownSymbol alias, aliased Data.Type.Equality.~ (alias Squeal.PostgreSQL.Alias.::: ty)) => Squeal.PostgreSQL.Alias.Aliasable alias (expression ty) (Squeal.PostgreSQL.Alias.Aliased expression aliased)
- Squeal.PostgreSQL.Alias: instance forall k (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, k)]) (field :: k) (aliases :: [GHC.Types.Symbol]) (subfields :: [(GHC.Types.Symbol, k)]). (Squeal.PostgreSQL.Alias.Has alias fields field, Squeal.PostgreSQL.Alias.HasAll aliases fields subfields) => Squeal.PostgreSQL.Alias.HasAll (alias : aliases) fields ((alias Squeal.PostgreSQL.Alias.::: field) : subfields)
- Squeal.PostgreSQL.Alias: instance forall k (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, k)]) (field :: k). Squeal.PostgreSQL.Alias.Has alias fields field => Squeal.PostgreSQL.Alias.HasIn fields (alias Squeal.PostgreSQL.Alias.::: field)
- Squeal.PostgreSQL.Alias: instance forall k (alias :: GHC.Types.Symbol) (tys :: [(GHC.Types.Symbol, k)]) (ty :: k) (expression :: k -> *). (GHC.TypeLits.KnownSymbol alias, tys Data.Type.Equality.~ '[alias Squeal.PostgreSQL.Alias.::: ty]) => Squeal.PostgreSQL.Alias.Aliasable alias (expression ty) (Data.SOP.NP.NP (Squeal.PostgreSQL.Alias.Aliased expression) tys)
- Squeal.PostgreSQL.Alias: instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Classes.Eq (expression ty) => GHC.Classes.Eq (Squeal.PostgreSQL.Alias.Aliased expression (alias Squeal.PostgreSQL.Alias.::: ty))
- Squeal.PostgreSQL.Alias: instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Classes.Ord (expression ty) => GHC.Classes.Ord (Squeal.PostgreSQL.Alias.Aliased expression (alias Squeal.PostgreSQL.Alias.::: ty))
- Squeal.PostgreSQL.Alias: instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Show.Show (expression ty) => GHC.Show.Show (Squeal.PostgreSQL.Alias.Aliased expression (alias Squeal.PostgreSQL.Alias.::: ty))
- Squeal.PostgreSQL.Alias: instance forall kind (alias :: GHC.Types.Symbol) (field :: kind) (fields :: [(GHC.Types.Symbol, kind)]). GHC.TypeLits.KnownSymbol alias => Squeal.PostgreSQL.Alias.Has alias ((alias Squeal.PostgreSQL.Alias.::: field) : fields) field
- Squeal.PostgreSQL.Alias: instance forall kind (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, kind)]) (field :: kind) (field' :: (GHC.Types.Symbol, kind)). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Alias.Has alias fields field) => Squeal.PostgreSQL.Alias.Has alias (field' : fields) field
- Squeal.PostgreSQL.Alias: instance forall kind (fields :: [(GHC.Types.Symbol, kind)]). Squeal.PostgreSQL.Alias.HasAll '[] fields '[]
- Squeal.PostgreSQL.Alias: renderAliased :: (forall ty. expression ty -> ByteString) -> Aliased expression aliased -> ByteString
- Squeal.PostgreSQL.Alias: type (:::) (alias :: Symbol) ty = '(alias, ty)
- Squeal.PostgreSQL.Alias: type HasUnique alias fields field = fields ~ '[alias ::: field]
- Squeal.PostgreSQL.Binary: Only :: x -> Only x
- Squeal.PostgreSQL.Binary: [fromOnly] :: Only x -> x
- Squeal.PostgreSQL.Binary: aliasedOid :: HasAliasedOid field => Word32
- Squeal.PostgreSQL.Binary: class FromField (pg :: (Symbol, NullityType)) (y :: (Symbol, Type))
- Squeal.PostgreSQL.Binary: class FromFixArray (dims :: [Nat]) (ty :: NullityType) (y :: Type)
- Squeal.PostgreSQL.Binary: class SListI result => FromRow (result :: RowType) y
- Squeal.PostgreSQL.Binary: class FromValue (pg :: PGType) (y :: Type)
- Squeal.PostgreSQL.Binary: class HasAliasedOid (field :: (Symbol, NullityType))
- Squeal.PostgreSQL.Binary: class HasOid (ty :: PGType)
- Squeal.PostgreSQL.Binary: class ToField (x :: (Symbol, Type)) (field :: (Symbol, NullityType))
- Squeal.PostgreSQL.Binary: class ToFixArray (x :: Type) (dims :: [Nat]) (array :: NullityType)
- Squeal.PostgreSQL.Binary: class ToNullityParam (x :: Type) (ty :: NullityType)
- Squeal.PostgreSQL.Binary: class ToParam (x :: Type) (pg :: PGType)
- Squeal.PostgreSQL.Binary: class SListI tys => ToParams (x :: Type) (tys :: [NullityType])
- Squeal.PostgreSQL.Binary: fromField :: FromField pg y => K (Maybe ByteString) pg -> (Either Text :.: P) y
- Squeal.PostgreSQL.Binary: fromFixArray :: FromFixArray dims ty y => Array y
- Squeal.PostgreSQL.Binary: fromRow :: FromRow result y => NP (K (Maybe ByteString)) result -> Either Text y
- Squeal.PostgreSQL.Binary: fromValue :: FromValue pg y => Value y
- Squeal.PostgreSQL.Binary: instance (Data.SOP.Constraint.SListI fields, Generics.SOP.Record.IsRecord x xs, Data.SOP.Constraint.AllZip Squeal.PostgreSQL.Binary.ToField xs fields, Data.SOP.Constraint.All Squeal.PostgreSQL.Binary.HasAliasedOid fields) => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Composite x) ('Squeal.PostgreSQL.Schema.PGcomposite fields)
- Squeal.PostgreSQL.Binary: instance (Data.SOP.Constraint.SListI result, Generics.SOP.Record.IsRecord y ys, Data.SOP.Constraint.AllZip Squeal.PostgreSQL.Binary.FromField result ys) => Squeal.PostgreSQL.Binary.FromRow result y
- Squeal.PostgreSQL.Binary: instance (Data.SOP.Constraint.SListI tys, Generics.SOP.Universe.IsProductType x xs, Data.SOP.Constraint.AllZip Squeal.PostgreSQL.Binary.ToNullityParam xs tys) => Squeal.PostgreSQL.Binary.ToParams x tys
- Squeal.PostgreSQL.Binary: instance (Generics.SOP.Universe.IsEnumType x, Generics.SOP.Universe.HasDatatypeInfo x, Squeal.PostgreSQL.PG.LabelsPG x Data.Type.Equality.~ labels) => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Enumerated x) ('Squeal.PostgreSQL.Schema.PGenum labels)
- Squeal.PostgreSQL.Binary: instance (Generics.SOP.Universe.IsEnumType y, Generics.SOP.Universe.HasDatatypeInfo y, Squeal.PostgreSQL.PG.LabelsPG y Data.Type.Equality.~ labels) => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGenum labels) (Squeal.PostgreSQL.PG.Enumerated y)
- Squeal.PostgreSQL.Binary: instance (Generics.SOP.Universe.IsProductType product xs, Squeal.PostgreSQL.List.Length xs Data.Type.Equality.~ dim, Data.SOP.Constraint.All ((Data.Type.Equality.~) x) xs, Squeal.PostgreSQL.Binary.ToFixArray x dims ty) => Squeal.PostgreSQL.Binary.ToFixArray product (dim : dims) ty
- Squeal.PostgreSQL.Binary: instance (Generics.SOP.Universe.IsProductType product ys, Squeal.PostgreSQL.List.Length ys Data.Type.Equality.~ dim, Data.SOP.Constraint.All ((Data.Type.Equality.~) y) ys, Squeal.PostgreSQL.Binary.FromFixArray dims ty y) => Squeal.PostgreSQL.Binary.FromFixArray (dim : dims) ty product
- Squeal.PostgreSQL.Binary: instance (Squeal.PostgreSQL.Binary.ToFixArray x dims ty, ty Data.Type.Equality.~ nullity pg, Squeal.PostgreSQL.Binary.HasOid pg) => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.FixArray x) ('Squeal.PostgreSQL.Schema.PGfixarray dims ty)
- Squeal.PostgreSQL.Binary: instance (Squeal.PostgreSQL.Binary.ToNullityParam x ty, ty Data.Type.Equality.~ nullity pg, Squeal.PostgreSQL.Binary.HasOid pg) => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.VarArray [x]) ('Squeal.PostgreSQL.Schema.PGvararray ty)
- Squeal.PostgreSQL.Binary: instance (Squeal.PostgreSQL.Binary.ToParam x pg, Squeal.PostgreSQL.Binary.HasOid pg) => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.VarArray (Data.Vector.Vector (GHC.Maybe.Maybe x))) ('Squeal.PostgreSQL.Schema.PGvararray ('Squeal.PostgreSQL.Schema.Null pg))
- Squeal.PostgreSQL.Binary: instance (Squeal.PostgreSQL.Binary.ToParam x pg, Squeal.PostgreSQL.Binary.HasOid pg) => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.VarArray (Data.Vector.Vector x)) ('Squeal.PostgreSQL.Schema.PGvararray ('Squeal.PostgreSQL.Schema.NotNull pg))
- Squeal.PostgreSQL.Binary: instance Data.Aeson.Types.FromJSON.FromJSON x => Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjson (Squeal.PostgreSQL.PG.Json x)
- Squeal.PostgreSQL.Binary: instance Data.Aeson.Types.FromJSON.FromJSON x => Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjsonb (Squeal.PostgreSQL.PG.Jsonb x)
- Squeal.PostgreSQL.Binary: instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Json x) 'Squeal.PostgreSQL.Schema.PGjson
- Squeal.PostgreSQL.Binary: instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Jsonb x) 'Squeal.PostgreSQL.Schema.PGjsonb
- Squeal.PostgreSQL.Binary: instance Data.Foldable.Foldable Squeal.PostgreSQL.Binary.Only
- Squeal.PostgreSQL.Binary: instance Data.Traversable.Traversable Squeal.PostgreSQL.Binary.Only
- Squeal.PostgreSQL.Binary: instance GHC.Base.Functor Squeal.PostgreSQL.Binary.Only
- Squeal.PostgreSQL.Binary: instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance GHC.Generics.Generic (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Binary.Only x)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromFixArray dims ty y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGfixarray dims ty) (Squeal.PostgreSQL.PG.FixArray y)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromRow fields y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGcomposite fields) (Squeal.PostgreSQL.PG.Composite y)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGbool GHC.Types.Bool
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGbytea Data.ByteString.Internal.ByteString
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGbytea Data.ByteString.Lazy.Internal.ByteString
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGdate Data.Time.Calendar.Days.Day
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGfloat4 GHC.Types.Float
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGfloat8 GHC.Types.Double
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGinet (Network.IP.Addr.NetAddr Network.IP.Addr.IP)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGint2 GHC.Int.Int16
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGint4 GHC.Int.Int32
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGint8 GHC.Int.Int64
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGinterval Data.Time.Clock.Internal.DiffTime.DiffTime
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjson Data.Aeson.Types.Internal.Value
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjsonb Data.Aeson.Types.Internal.Value
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGmoney Squeal.PostgreSQL.PG.Money
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGnumeric Data.Scientific.Scientific
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtext Data.Text.Internal.Lazy.Text
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtext Data.Text.Internal.Text
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtext GHC.Base.String
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtime Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtimestamp Data.Time.LocalTime.Internal.LocalTime.LocalTime
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtimestamptz Data.Time.Clock.Internal.UTCTime.UTCTime
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtimetz (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGuuid Data.UUID.Types.Internal.UUID
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGchar 1) GHC.Types.Char
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromField (column Squeal.PostgreSQL.Alias.::: 'Squeal.PostgreSQL.Schema.NotNull pg) (column Squeal.PostgreSQL.Alias.::: y)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromField (column Squeal.PostgreSQL.Alias.::: 'Squeal.PostgreSQL.Schema.Null pg) (column Squeal.PostgreSQL.Alias.::: GHC.Maybe.Maybe y)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromFixArray '[] ('Squeal.PostgreSQL.Schema.NotNull pg) y
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromFixArray '[] ('Squeal.PostgreSQL.Schema.Null pg) (GHC.Maybe.Maybe y)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGvararray ('Squeal.PostgreSQL.Schema.NotNull pg)) (Squeal.PostgreSQL.PG.VarArray (Data.Vector.Vector y))
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGvararray ('Squeal.PostgreSQL.Schema.NotNull pg)) (Squeal.PostgreSQL.PG.VarArray [y])
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGvararray ('Squeal.PostgreSQL.Schema.Null pg)) (Squeal.PostgreSQL.PG.VarArray (Data.Vector.Vector (GHC.Maybe.Maybe y)))
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGvararray ('Squeal.PostgreSQL.Schema.Null pg)) (Squeal.PostgreSQL.PG.VarArray [GHC.Maybe.Maybe y])
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGbool
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGbytea
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGdate
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGfloat4
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGfloat8
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGinet
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGint2
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGint4
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGint8
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGjson
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGjsonb
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGnumeric
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtext
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtime
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtimestamp
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtimestamptz
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtimetz
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGuuid
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid ('Squeal.PostgreSQL.Schema.PGchar n)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid ('Squeal.PostgreSQL.Schema.PGvarchar n)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.HasOid ty => Squeal.PostgreSQL.Binary.HasAliasedOid (alias Squeal.PostgreSQL.Alias.::: nullity ty)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToNullityParam x ty => Squeal.PostgreSQL.Binary.ToField (alias Squeal.PostgreSQL.Alias.::: x) (alias Squeal.PostgreSQL.Alias.::: ty)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToNullityParam x ty => Squeal.PostgreSQL.Binary.ToFixArray x '[] ty
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone) 'Squeal.PostgreSQL.Schema.PGtimetz
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam (Network.IP.Addr.NetAddr Network.IP.Addr.IP) 'Squeal.PostgreSQL.Schema.PGinet
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Aeson.Types.Internal.Value 'Squeal.PostgreSQL.Schema.PGjson
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Aeson.Types.Internal.Value 'Squeal.PostgreSQL.Schema.PGjsonb
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.ByteString.Internal.ByteString 'Squeal.PostgreSQL.Schema.PGbytea
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.ByteString.Lazy.Internal.ByteString 'Squeal.PostgreSQL.Schema.PGbytea
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Scientific.Scientific 'Squeal.PostgreSQL.Schema.PGnumeric
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Text.Internal.Lazy.Text 'Squeal.PostgreSQL.Schema.PGtext
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Text.Internal.Text 'Squeal.PostgreSQL.Schema.PGtext
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Time.Calendar.Days.Day 'Squeal.PostgreSQL.Schema.PGdate
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Time.Clock.Internal.DiffTime.DiffTime 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Time.Clock.Internal.UTCTime.UTCTime 'Squeal.PostgreSQL.Schema.PGtimestamptz
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Time.LocalTime.Internal.LocalTime.LocalTime 'Squeal.PostgreSQL.Schema.PGtimestamp
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay 'Squeal.PostgreSQL.Schema.PGtime
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Data.UUID.Types.Internal.UUID 'Squeal.PostgreSQL.Schema.PGuuid
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Base.String 'Squeal.PostgreSQL.Schema.PGtext
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Int.Int16 'Squeal.PostgreSQL.Schema.PGint2
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Int.Int32 'Squeal.PostgreSQL.Schema.PGint4
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Int.Int64 'Squeal.PostgreSQL.Schema.PGint8
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Bool 'Squeal.PostgreSQL.Schema.PGbool
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Char ('Squeal.PostgreSQL.Schema.PGchar 1)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Double 'Squeal.PostgreSQL.Schema.PGfloat8
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Float 'Squeal.PostgreSQL.Schema.PGfloat4
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Word.Word16 'Squeal.PostgreSQL.Schema.PGint2
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Word.Word32 'Squeal.PostgreSQL.Schema.PGint4
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam GHC.Word.Word64 'Squeal.PostgreSQL.Schema.PGint8
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam Squeal.PostgreSQL.PG.Money 'Squeal.PostgreSQL.Schema.PGmoney
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam x pg => Squeal.PostgreSQL.Binary.ToNullityParam (GHC.Maybe.Maybe x) ('Squeal.PostgreSQL.Schema.Null pg)
- Squeal.PostgreSQL.Binary: instance Squeal.PostgreSQL.Binary.ToParam x pg => Squeal.PostgreSQL.Binary.ToNullityParam x ('Squeal.PostgreSQL.Schema.NotNull pg)
- Squeal.PostgreSQL.Binary: newtype Only x
- Squeal.PostgreSQL.Binary: oid :: HasOid ty => Word32
- Squeal.PostgreSQL.Binary: toField :: ToField x field => P x -> K (Maybe Encoding) field
- Squeal.PostgreSQL.Binary: toFixArray :: ToFixArray x dims array => x -> K (K Array dims) array
- Squeal.PostgreSQL.Binary: toNullityParam :: ToNullityParam x ty => x -> K (Maybe Encoding) ty
- Squeal.PostgreSQL.Binary: toParam :: ToParam x pg => x -> K Encoding pg
- Squeal.PostgreSQL.Binary: toParams :: ToParams x tys => x -> NP (K (Maybe Encoding)) tys
- Squeal.PostgreSQL.Definition: OnDeleteCascade :: OnDeleteClause
- Squeal.PostgreSQL.Definition: OnDeleteNoAction :: OnDeleteClause
- Squeal.PostgreSQL.Definition: OnDeleteRestrict :: OnDeleteClause
- Squeal.PostgreSQL.Definition: OnUpdateCascade :: OnUpdateClause
- Squeal.PostgreSQL.Definition: OnUpdateNoAction :: OnUpdateClause
- Squeal.PostgreSQL.Definition: OnUpdateRestrict :: OnUpdateClause
- Squeal.PostgreSQL.Definition: UnsafeAlterColumn :: ByteString -> AlterColumn
- Squeal.PostgreSQL.Definition: UnsafeAlterTable :: ByteString -> AlterTable
- Squeal.PostgreSQL.Definition: UnsafeColumnTypeExpression :: ByteString -> ColumnTypeExpression
- Squeal.PostgreSQL.Definition: UnsafeTableConstraintExpression :: ByteString -> TableConstraintExpression
- Squeal.PostgreSQL.Definition: [renderAlterColumn] :: AlterColumn -> ByteString
- Squeal.PostgreSQL.Definition: [renderAlterTable] :: AlterTable -> ByteString
- Squeal.PostgreSQL.Definition: [renderColumnTypeExpression] :: ColumnTypeExpression -> ByteString
- Squeal.PostgreSQL.Definition: [renderTableConstraintExpression] :: TableConstraintExpression -> ByteString
- Squeal.PostgreSQL.Definition: addColumn :: (AddColumn ty, KnownSymbol column, Has sch schemas schema, Has tab schema ( 'Table table0), table0 ~ (constraints :=> columns)) => Alias column -> ColumnTypeExpression schemas ty -> AlterTable sch tab schemas (constraints :=> Create column ty columns)
- Squeal.PostgreSQL.Definition: addConstraint :: (KnownSymbol alias, Has sch schemas schema, Has tab schema ( 'Table table0), table0 ~ (constraints :=> columns), table1 ~ (Create alias constraint constraints :=> columns)) => Alias alias -> TableConstraintExpression sch tab schemas constraint -> AlterTable sch tab schemas table1
- Squeal.PostgreSQL.Definition: alterColumn :: (KnownSymbol column, Has sch schemas schema, Has tab schema ( 'Table table0), table0 ~ (constraints :=> columns), Has column columns ty0, table1 ~ (constraints :=> Alter column ty1 columns)) => Alias column -> AlterColumn schemas ty0 ty1 -> AlterTable sch tab schemas table1
- Squeal.PostgreSQL.Definition: alterTable :: (Has sch schemas schema, Has tab schema ( 'Table table0)) => QualifiedAlias sch tab -> AlterTable sch tab schemas table1 -> Definition schemas (Alter sch (Alter tab ( 'Table table1) schema) schemas)
- Squeal.PostgreSQL.Definition: alterTableRename :: (KnownSymbol table0, KnownSymbol table1) => Alias table0 -> Alias table1 -> Definition schema (Rename table0 table1 schema)
- Squeal.PostgreSQL.Definition: alterType :: ColumnTypeExpression schemas ty -> AlterColumn schemas ty0 ty
- Squeal.PostgreSQL.Definition: bigserial :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint8)
- Squeal.PostgreSQL.Definition: check :: (Has sch schemas schema, Has tab schema ( 'Table table), HasAll aliases (TableToRow table) subcolumns) => NP Alias aliases -> (forall t. Condition '[] '[] 'Ungrouped schemas '[] '[t ::: subcolumns]) -> TableConstraintExpression sch tab schemas ( 'Check aliases)
- Squeal.PostgreSQL.Definition: class AddColumn ty
- Squeal.PostgreSQL.Definition: class FieldTyped schemas ty
- Squeal.PostgreSQL.Definition: createDomain :: (Has sch schemas schema, KnownSymbol dom) => QualifiedAlias sch dom -> (forall nullity. TypeExpression schemas (nullity ty)) -> (forall tab. Condition '[] '[] 'Ungrouped schemas '[] '[tab ::: '["value" ::: 'Null ty]]) -> Definition schemas (Alter sch (Create alias ( 'Typedef ty) schema) schemas)
- Squeal.PostgreSQL.Definition: createSchema :: KnownSymbol sch => Alias sch -> Definition schemas (Create sch '[] schemas)
- Squeal.PostgreSQL.Definition: createSchemaIfNotExists :: (KnownSymbol sch, Has sch schemas schema) => Alias sch -> Definition schemas schemas
- Squeal.PostgreSQL.Definition: createTable :: (KnownSymbol sch, KnownSymbol tab, columns ~ (col : cols), SListI columns, SListI constraints, Has sch schemas0 schema0, schemas1 ~ Alter sch (Create tab ( 'Table (constraints :=> columns)) schema0) schemas0) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression schemas0)) columns -> NP (Aliased (TableConstraintExpression sch tab schemas1)) constraints -> Definition schemas0 schemas1
- Squeal.PostgreSQL.Definition: createTableIfNotExists :: (Has sch schemas schema, Has tab schema ( 'Table (constraints :=> columns)), SListI columns, SListI constraints) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression schemas)) columns -> NP (Aliased (TableConstraintExpression sch tab schemas)) constraints -> Definition schemas schemas
- Squeal.PostgreSQL.Definition: createTypeComposite :: (KnownSymbol ty, Has sch schemas schema, SListI fields) => QualifiedAlias sch ty -> NP (Aliased (TypeExpression schemas)) fields -> Definition schemas (Alter sch (Create ty ( 'Typedef ( 'PGcomposite fields)) schema) schemas)
- Squeal.PostgreSQL.Definition: createTypeCompositeFrom :: forall hask sch ty schemas schema. (All (FieldTyped schemas) (RowPG hask), KnownSymbol ty, Has sch schemas schema) => QualifiedAlias sch ty -> Definition schemas (Alter sch (Create ty ( 'Typedef (PG (Composite hask))) schema) schemas)
- Squeal.PostgreSQL.Definition: createTypeEnum :: (KnownSymbol enum, Has sch schemas schema, All KnownSymbol labels) => QualifiedAlias sch enum -> NP PGlabel labels -> Definition schemas (Alter sch (Create enum ( 'Typedef ( 'PGenum labels)) schema) schemas)
- Squeal.PostgreSQL.Definition: createTypeEnumFrom :: forall hask sch enum schemas schema. (Generic hask, All KnownSymbol (LabelsPG hask), KnownSymbol enum, Has sch schemas schema) => QualifiedAlias sch enum -> Definition schemas (Alter sch (Create enum ( 'Typedef (PG (Enumerated hask))) schema) schemas)
- Squeal.PostgreSQL.Definition: createView :: (KnownSymbol sch, KnownSymbol vw, Has sch schemas schema) => QualifiedAlias sch vw -> Query '[] '[] schemas '[] view -> Definition schemas (Alter sch (Create vw ( 'View view) schema) schemas)
- Squeal.PostgreSQL.Definition: data OnDeleteClause
- Squeal.PostgreSQL.Definition: data OnUpdateClause
- Squeal.PostgreSQL.Definition: default_ :: Expression '[] '[] 'Ungrouped schemas '[] '[] ty -> ColumnTypeExpression schemas ( 'NoDef :=> ty) -> ColumnTypeExpression schemas ( 'Def :=> ty)
- Squeal.PostgreSQL.Definition: dropColumn :: (KnownSymbol column, Has sch schemas schema, Has tab schema ( 'Table table0), table0 ~ (constraints :=> columns), table1 ~ (constraints :=> Drop column columns)) => Alias column -> AlterTable sch tab schemas table1
- Squeal.PostgreSQL.Definition: dropConstraint :: (KnownSymbol constraint, Has sch schemas schema, Has tab schema ( 'Table table0), table0 ~ (constraints :=> columns), table1 ~ (Drop constraint constraints :=> columns)) => Alias constraint -> AlterTable sch tab schemas table1
- Squeal.PostgreSQL.Definition: dropDefault :: AlterColumn schemas ( 'Def :=> ty) ( 'NoDef :=> ty)
- Squeal.PostgreSQL.Definition: dropNotNull :: AlterColumn schemas (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)
- Squeal.PostgreSQL.Definition: dropSchema :: Has sch schemas schema => Alias sch -> Definition schemas (Drop sch schemas)
- Squeal.PostgreSQL.Definition: dropTable :: (Has sch schemas schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> Definition schemas (Alter sch (Drop tab schema) schemas)
- Squeal.PostgreSQL.Definition: dropType :: (Has sch schemas schema, Has td schema ( 'Typedef ty)) => QualifiedAlias sch td -> Definition schemas (Alter sch (Drop td schema) schemas)
- Squeal.PostgreSQL.Definition: dropView :: (Has sch schemas schema, Has vw schema ( 'View view)) => QualifiedAlias sch vw -> Definition schemas (Alter sch (Drop vw schema) schemas)
- Squeal.PostgreSQL.Definition: fieldtype :: FieldTyped schemas ty => Aliased (TypeExpression schemas) ty
- Squeal.PostgreSQL.Definition: foreignKey :: ForeignKeyed schemas sch schema child parent table reftable columns refcolumns constraints cols reftys tys => NP Alias columns -> Alias parent -> NP Alias refcolumns -> OnDeleteClause -> OnUpdateClause -> TableConstraintExpression sch child schemas ( 'ForeignKey columns parent refcolumns)
- Squeal.PostgreSQL.Definition: instance (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Expression.Type.PGTyped schemas ty) => Squeal.PostgreSQL.Definition.FieldTyped schemas (alias Squeal.PostgreSQL.Alias.::: ty)
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.OnDeleteClause
- Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.OnUpdateClause
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.OnDeleteClause
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.OnUpdateClause
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.OnDeleteClause
- Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.OnUpdateClause
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.OnDeleteClause
- Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.OnUpdateClause
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show Squeal.PostgreSQL.Definition.OnDeleteClause
- Squeal.PostgreSQL.Definition: instance GHC.Show.Show Squeal.PostgreSQL.Definition.OnUpdateClause
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Definition.AddColumn ('Squeal.PostgreSQL.Schema.Def Squeal.PostgreSQL.Schema.:=> ty)
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Definition.AddColumn ('Squeal.PostgreSQL.Schema.NoDef Squeal.PostgreSQL.Schema.:=> 'Squeal.PostgreSQL.Schema.Null ty)
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.OnDeleteClause
- Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.OnUpdateClause
- Squeal.PostgreSQL.Definition: manipDefinition :: Manipulation '[] schemas '[] '[] -> Definition schemas schemas
- Squeal.PostgreSQL.Definition: newtype AlterColumn (schemas :: SchemasType) (ty0 :: ColumnType) (ty1 :: ColumnType)
- Squeal.PostgreSQL.Definition: newtype AlterTable (sch :: Symbol) (tab :: Symbol) (schemas :: SchemasType) (table :: TableType)
- Squeal.PostgreSQL.Definition: newtype ColumnTypeExpression (schemas :: SchemasType) (ty :: ColumnType)
- Squeal.PostgreSQL.Definition: newtype TableConstraintExpression (sch :: Symbol) (tab :: Symbol) (schemas :: SchemasType) (constraint :: TableConstraint)
- Squeal.PostgreSQL.Definition: notNullable :: TypeExpression schemas (nullity ty) -> ColumnTypeExpression schemas ( 'NoDef :=> 'NotNull ty)
- Squeal.PostgreSQL.Definition: nullable :: TypeExpression schemas (nullity ty) -> ColumnTypeExpression schemas ( 'NoDef :=> 'Null ty)
- Squeal.PostgreSQL.Definition: primaryKey :: (Has sch schemas schema, Has tab schema ( 'Table table), HasAll aliases (TableToColumns table) subcolumns, AllNotNull subcolumns) => NP Alias aliases -> TableConstraintExpression sch tab schemas ( 'PrimaryKey aliases)
- Squeal.PostgreSQL.Definition: renameColumn :: (KnownSymbol column0, KnownSymbol column1, Has sch schemas schema, Has tab schema ( 'Table table0), table0 ~ (constraints :=> columns), table1 ~ (constraints :=> Rename column0 column1 columns)) => Alias column0 -> Alias column1 -> AlterTable sch tab schemas table1
- Squeal.PostgreSQL.Definition: serial :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint4)
- Squeal.PostgreSQL.Definition: serial2 :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint2)
- Squeal.PostgreSQL.Definition: serial4 :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint4)
- Squeal.PostgreSQL.Definition: serial8 :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint8)
- Squeal.PostgreSQL.Definition: setDefault :: Expression '[] '[] 'Ungrouped schemas '[] '[] ty -> AlterColumn schemas (constraint :=> ty) ( 'Def :=> ty)
- Squeal.PostgreSQL.Definition: setNotNull :: AlterColumn schemas (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)
- Squeal.PostgreSQL.Definition: smallserial :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint2)
- Squeal.PostgreSQL.Definition: type ForeignKeyed schemas sch schema child parent table reftable columns refcolumns constraints cols reftys tys = (Has sch schemas schema, Has child schema ( 'Table table), Has parent schema ( 'Table reftable), HasAll columns (TableToColumns table) tys, reftable ~ (constraints :=> cols), HasAll refcolumns cols reftys, AllZip SamePGType tys reftys, Uniquely refcolumns constraints)
- Squeal.PostgreSQL.Definition: unique :: (Has sch schemas schema, Has tab schema ( 'Table table), HasAll aliases (TableToRow table) subcolumns) => NP Alias aliases -> TableConstraintExpression sch tab schemas ( 'Unique aliases)
- Squeal.PostgreSQL.Expression: K :: a -> K a
- Squeal.PostgreSQL.Expression: instance (GHC.TypeLits.KnownSymbol label, Squeal.PostgreSQL.List.In label labels) => Squeal.PostgreSQL.Schema.IsPGlabel label (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null ('Squeal.PostgreSQL.Schema.PGenum labels)))
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty) => Squeal.PostgreSQL.Alias.IsQualified tab col (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from ty)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys) => Squeal.PostgreSQL.Alias.IsQualified tab col (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from ty)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Alias.::: ty)) => Squeal.PostgreSQL.Alias.IsQualified tab col (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from) column)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => Squeal.PostgreSQL.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from)) columns)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys, tys Data.Type.Equality.~ '[ty]) => Squeal.PostgreSQL.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from) tys)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Alias.::: ty)) => Squeal.PostgreSQL.Alias.IsQualified tab col (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from) column)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => Squeal.PostgreSQL.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from)) columns)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, tys Data.Type.Equality.~ '[ty]) => Squeal.PostgreSQL.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from) tys)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from ty)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from ty)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Alias.::: ty)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from) column)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from)) columns)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, Squeal.PostgreSQL.Alias.GroupedBy tab col bys, tys Data.Type.Equality.~ '[ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from) tys)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Alias.::: ty)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from) column)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from)) columns)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row, Squeal.PostgreSQL.Alias.Has col row ty, tys Data.Type.Equality.~ '[ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from) tys)
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.List.In ty Squeal.PostgreSQL.Schema.PGNum, Squeal.PostgreSQL.List.In ty Squeal.PostgreSQL.Schema.PGFloating) => GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null ty))
- Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.List.In ty Squeal.PostgreSQL.Schema.PGNum, Squeal.PostgreSQL.List.In ty Squeal.PostgreSQL.Schema.PGFloating) => GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null ty))
- Squeal.PostgreSQL.Expression: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression: instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtext))
- Squeal.PostgreSQL.Expression: instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsquery))
- Squeal.PostgreSQL.Expression: instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsvector))
- Squeal.PostgreSQL.Expression: instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtext))
- Squeal.PostgreSQL.Expression: instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsvector))
- Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGjsonb))
- Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtext))
- Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsvector))
- Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null ('Squeal.PostgreSQL.Schema.PGvararray ty)))
- Squeal.PostgreSQL.Expression: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Schema.PGjsonb
- Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Schema.PGtsquery
- Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset ('Squeal.PostgreSQL.Schema.PGvararray ty)
- Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.List.In ty Squeal.PostgreSQL.Schema.PGNum => GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null ty))
- Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression: newtype K a (b :: k) :: forall k. () => Type -> k -> Type
- Squeal.PostgreSQL.Expression: type FunctionN xs y = forall outer commons grp schemas params from. NP (Expression outer commons grp schemas params from) xs " inputs" -> Expression outer commons grp schemas params from y " output"
- Squeal.PostgreSQL.Expression: unK :: () => K a b -> a
- Squeal.PostgreSQL.Expression: unsafeUnaryOpL :: ByteString -> x :--> y
- Squeal.PostgreSQL.Expression: unsafeUnaryOpR :: ByteString -> x :--> y
- Squeal.PostgreSQL.Expression.Aggregate: All :: expr ty -> Distinction
- Squeal.PostgreSQL.Expression.Aggregate: Distinct :: expr ty -> Distinction
- Squeal.PostgreSQL.Expression.Aggregate: data Distinction (expr :: kind -> Type) (ty :: kind)
- Squeal.PostgreSQL.Expression.Aggregate: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from) ty)
- Squeal.PostgreSQL.Expression.Aggregate: instance Data.SOP.Constraint.SListI tys => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from)) tys)
- Squeal.PostgreSQL.Expression.Aggregate: instance Squeal.PostgreSQL.Expression.Aggregate.Aggregate (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from)) (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from))) (Squeal.PostgreSQL.Expression.Expression outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from)
- Squeal.PostgreSQL.Expression.Aggregate: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from) ty)
- Squeal.PostgreSQL.Expression.Aggregate: instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Classes.Eq (expr ty) => GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
- Squeal.PostgreSQL.Expression.Aggregate: instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Classes.Ord (expr ty) => GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
- Squeal.PostgreSQL.Expression.Aggregate: instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
- Squeal.PostgreSQL.Expression.Aggregate: instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Show.Show (expr ty) => GHC.Show.Show (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
- Squeal.PostgreSQL.Expression.Collection: array :: [Expression outer commons grp schemas params from ty] -> Expression outer commons grp schemas params from (null ( 'PGvararray ty))
- Squeal.PostgreSQL.Expression.Collection: array1 :: (n ~ Length tys, All ((~) ty) tys) => NP (Expression outer commons grp schemas params from) tys -> Expression outer commons grp schemas params from (null ( 'PGfixarray '[n] ty))
- Squeal.PostgreSQL.Expression.Collection: array2 :: (All ((~) tys) tyss, All SListI tyss, Length tyss ~ n1, All ((~) ty) tys, Length tys ~ n2) => NP (NP (Expression outer commons grp schemas params from)) tyss -> Expression outer commons grp schemas params from (null ( 'PGfixarray '[n1, n2] ty))
- Squeal.PostgreSQL.Expression.Collection: cardinality :: null ( 'PGvararray ty) :--> null 'PGint8
- Squeal.PostgreSQL.Expression.Collection: field :: (Has sch schemas schema, Has tydef schema ( 'Typedef ( 'PGcomposite row)), Has field row ty) => QualifiedAlias sch tydef -> Alias field -> Expression outer commons grp schemas params from ( 'NotNull ( 'PGcomposite row)) -> Expression outer commons grp schemas params from ty
- Squeal.PostgreSQL.Expression.Collection: index :: Word64 -> null ( 'PGvararray ty) :--> NullifyType ty
- Squeal.PostgreSQL.Expression.Collection: row :: SListI row => NP (Aliased (Expression outer commons grp schemas params from)) row -> Expression outer commons grp schemas params from (null ( 'PGcomposite row))
- Squeal.PostgreSQL.Expression.Collection: unnest :: SetOfFunction "unnest" (null ( 'PGvararray ty)) '["unnest" ::: ty]
- Squeal.PostgreSQL.Expression.Json: instance (Squeal.PostgreSQL.Expression.Json.JsonBuildObject tys, Squeal.PostgreSQL.List.In key Squeal.PostgreSQL.Schema.PGJsonKey) => Squeal.PostgreSQL.Expression.Json.JsonBuildObject ('Squeal.PostgreSQL.Schema.NotNull key : value : tys)
- Squeal.PostgreSQL.Expression.Literal: class Literal hask
- Squeal.PostgreSQL.Expression.Literal: instance Data.Aeson.Types.ToJSON.ToJSON hask => Squeal.PostgreSQL.Expression.Literal.Literal (Squeal.PostgreSQL.PG.Json hask)
- Squeal.PostgreSQL.Expression.Literal: instance Data.Aeson.Types.ToJSON.ToJSON hask => Squeal.PostgreSQL.Expression.Literal.Literal (Squeal.PostgreSQL.PG.Jsonb hask)
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Enumerated enum) (Squeal.PostgreSQL.PG.PG (Squeal.PostgreSQL.PG.Enumerated enum)) => Squeal.PostgreSQL.Expression.Literal.Literal (Squeal.PostgreSQL.PG.Enumerated enum)
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal Data.Text.Internal.Lazy.Text
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal Data.Text.Internal.Text
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Base.String
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Int.Int16
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Int.Int32
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Int.Int64
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Bool
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Char
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Double
- Squeal.PostgreSQL.Expression.Literal: instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Float
- Squeal.PostgreSQL.Expression.Literal: literal :: Literal hask => hask -> Expr (null (PG hask))
- Squeal.PostgreSQL.Expression.SetOf: generateSeries :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric] => SetOfFunctionN "generate_series" '[null ty, null ty] '["generate_series" ::: null ty]
- Squeal.PostgreSQL.Expression.SetOf: generateSeriesStep :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric] => SetOfFunctionN "generate_series" '[null ty, null ty, null ty] '["generate_series" ::: null ty]
- Squeal.PostgreSQL.Expression.SetOf: generateSeriesTimestamp :: ty `In` '[ 'PGtimestamp, 'PGtimestamptz] => SetOfFunctionN "generate_series" '[null ty, null ty, null 'PGinterval] '["generate_series" ::: null ty]
- Squeal.PostgreSQL.Expression.SetOf: type SetOfFunction fun ty setof = forall outer commons schemas params. Expression outer commons 'Ungrouped schemas params '[] ty " input" -> FromClause outer commons schemas params '[fun ::: setof] " output"
- Squeal.PostgreSQL.Expression.SetOf: type SetOfFunctionN fun tys setof = forall outer commons schemas params. NP (Expression outer commons 'Ungrouped schemas params '[]) tys " inputs" -> FromClause outer commons schemas params '[fun ::: setof] " output"
- Squeal.PostgreSQL.Expression.SetOf: unsafeSetOfFunction :: forall fun ty setof. KnownSymbol fun => SetOfFunction fun ty setof
- Squeal.PostgreSQL.Expression.SetOf: unsafeSetOfFunctionN :: forall fun tys setof. (SListI tys, KnownSymbol fun) => SetOfFunctionN fun tys setof
- Squeal.PostgreSQL.Expression.Sort: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Sort.SortExpression outer commons grp schemas params from)
- Squeal.PostgreSQL.Expression.Sort: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Sort.SortExpression outer commons grp schemas params from)
- Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGdate 'Squeal.PostgreSQL.Schema.PGint4
- Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGinterval 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtime 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtimestamp 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtimestamptz 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtimetz 'Squeal.PostgreSQL.Schema.PGinterval
- Squeal.PostgreSQL.Expression.Type: instance (Data.SOP.Constraint.All GHC.TypeNats.KnownNat dims, Squeal.PostgreSQL.Expression.Type.PGTyped schemas ty) => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGfixarray dims ty))
- Squeal.PostgreSQL.Expression.Type: instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGchar n))
- Squeal.PostgreSQL.Expression.Type: instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGvarchar n))
- Squeal.PostgreSQL.Expression.Type: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty)
- Squeal.PostgreSQL.Expression.Type: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty)
- Squeal.PostgreSQL.Expression.Type: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty)
- Squeal.PostgreSQL.Expression.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty)
- Squeal.PostgreSQL.Expression.Type: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGbool)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGbytea)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGdate)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGfloat4)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGfloat8)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGint2)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGint4)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGint8)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGinterval)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGjson)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGjsonb)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGmoney)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGnumeric)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtext)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtime)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtimestamp)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtimestamptz)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtimetz)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtsquery)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtsvector)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGuuid)
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas ty => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGvararray ty))
- Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty)
- Squeal.PostgreSQL.Expression.Window: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression.Window: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression.Window: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression.Window: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression.Window: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Expression.Aggregate.Aggregate (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from) (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from)) (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from)
- Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Expression.Sort.OrderBy Squeal.PostgreSQL.Expression.Window.WindowDefinition
- Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowDefinition outer commons schemas from grp params)
- Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty)
- Squeal.PostgreSQL.Expression.Window: type WinFun1 x y = forall outer commons grp schemas params from. Expression outer commons grp schemas params from x " input" -> WindowFunction outer commons grp schemas params from y " output"
- Squeal.PostgreSQL.Expression.Window: type WinFunN xs y = forall outer commons grp schemas params from. NP (Expression outer commons grp schemas params from) xs " inputs" -> WindowFunction outer commons grp schemas params from y " output"
- Squeal.PostgreSQL.List: (*:) :: f x -> f y -> NP f '[x, y]
- Squeal.PostgreSQL.List: [:*] :: forall k (a :: k -> Type) (b :: [k]) (x :: k) (xs :: [k]). () => a x -> NP a xs -> NP a (x : xs)
- Squeal.PostgreSQL.List: [:>>] :: p x0 x1 -> AlignedList p x1 x2 -> AlignedList p x0 x2
- Squeal.PostgreSQL.List: [Done] :: AlignedList p x x
- Squeal.PostgreSQL.List: [Nil] :: forall k (a :: k -> Type) (b :: [k]). () => NP a ([] :: [k])
- Squeal.PostgreSQL.List: also :: Additional expr => expr ys -> expr xs -> expr (Join xs ys)
- Squeal.PostgreSQL.List: class Additional expr
- Squeal.PostgreSQL.List: data AlignedList p x0 x1
- Squeal.PostgreSQL.List: data NP (a :: k -> Type) (b :: [k]) :: forall k. () => k -> Type -> [k] -> Type
- Squeal.PostgreSQL.List: disjoin :: forall xs ys expr. SListI xs => NP expr (Join xs ys) -> (NP expr xs, NP expr ys)
- Squeal.PostgreSQL.List: extractList :: (forall a0 a1. p a0 a1 -> b) -> AlignedList p x0 x1 -> [b]
- Squeal.PostgreSQL.List: infixl 9 *:
- Squeal.PostgreSQL.List: infixr 5 :*
- Squeal.PostgreSQL.List: infixr 7 :>>
- Squeal.PostgreSQL.List: instance forall a (expr :: a -> *). Squeal.PostgreSQL.List.Additional (Data.SOP.NP.NP expr)
- Squeal.PostgreSQL.List: instance forall k (p :: k -> k -> *) (x0 :: k) (x1 :: k). (forall (t0 :: k) (t1 :: k). Squeal.PostgreSQL.Render.RenderSQL (p t0 t1)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.List.AlignedList p x0 x1)
- Squeal.PostgreSQL.List: instance forall k (p :: k -> k -> *). Control.Category.Category (Squeal.PostgreSQL.List.AlignedList p)
- Squeal.PostgreSQL.List: mapAligned :: (forall z0 z1. p z0 z1 -> q z0 z1) -> AlignedList p x0 x1 -> AlignedList q x0 x1
- Squeal.PostgreSQL.List: single :: p x0 x1 -> AlignedList p x0 x1
- Squeal.PostgreSQL.List: type family Length (xs :: [k]) :: Nat
- Squeal.PostgreSQL.Manipulation: [Default] :: Optional expr ( 'Def :=> ty)
- Squeal.PostgreSQL.Manipulation: [DoNothing] :: ConflictAction tab commons schemas params columns
- Squeal.PostgreSQL.Manipulation: [DoUpdate] :: (row ~ ColumnsToRow columns, SListI columns, columns ~ (col0 : cols), All (HasIn columns) subcolumns, AllUnique subcolumns) => NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[tab ::: row, "excluded" ::: row]))) subcolumns -> [Condition '[] commons 'Ungrouped schemas params '[tab ::: row, "excluded" ::: row]] -> ConflictAction tab commons schemas params columns
- Squeal.PostgreSQL.Manipulation: [NoUsing] :: UsingClause commons schemas params '[]
- Squeal.PostgreSQL.Manipulation: [OnConflictDoRaise] :: ConflictClause tab commons schemas params table
- Squeal.PostgreSQL.Manipulation: [OnConflict] :: ConflictTarget constraints -> ConflictAction tab commons schemas params columns -> ConflictClause tab commons schemas params (constraints :=> columns)
- Squeal.PostgreSQL.Manipulation: [OnConstraint] :: Has con constraints constraint => Alias con -> ConflictTarget constraints
- Squeal.PostgreSQL.Manipulation: [Select] :: SListI columns => NP (Aliased (Optional (Expression '[] commons grp schemas params from))) columns -> TableExpression '[] commons grp schemas params from -> QueryClause commons schemas params columns
- Squeal.PostgreSQL.Manipulation: [Set] :: expr ty -> Optional expr (def :=> ty)
- Squeal.PostgreSQL.Manipulation: [Subquery] :: ColumnsToRow columns ~ row => Query '[] commons schemas params row -> QueryClause commons schemas params columns
- Squeal.PostgreSQL.Manipulation: [Using] :: FromClause '[] commons schemas params from -> UsingClause commons schemas params from
- Squeal.PostgreSQL.Manipulation: [Values] :: SListI columns => NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[]))) columns -> [NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[]))) columns] -> QueryClause commons schemas params columns
- Squeal.PostgreSQL.Manipulation: data ConflictAction tab commons schemas params columns
- Squeal.PostgreSQL.Manipulation: data ConflictClause tab commons schemas params table
- Squeal.PostgreSQL.Manipulation: data ConflictTarget constraints
- Squeal.PostgreSQL.Manipulation: data Optional expr ty
- Squeal.PostgreSQL.Manipulation: data QueryClause commons schemas params columns
- Squeal.PostgreSQL.Manipulation: data UsingClause commons schemas params from
- Squeal.PostgreSQL.Manipulation: deleteFrom :: (SListI row1, db ~ (commons :=> schemas), Has sch schemas schema, Has tab schema ( 'Table table), row0 ~ TableToRow table, columns ~ TableToColumns table) => QualifiedAlias sch tab -> UsingClause commons schemas params from -> Condition '[] commons 'Ungrouped schemas params ((tab ::: row0) : from) -> ReturningClause commons schemas params '[tab ::: row0] row1 -> Manipulation commons schemas params row1
- Squeal.PostgreSQL.Manipulation: deleteFrom_ :: (db ~ (commons :=> schemas), Has sch schemas schema, Has tab schema ( 'Table table), row ~ TableToRow table, columns ~ TableToColumns table) => QualifiedAlias sch tab -> Condition '[] commons 'Ungrouped schemas params '[tab ::: row] -> Manipulation commons schemas params '[]
- Squeal.PostgreSQL.Manipulation: insertInto :: (Has sch schemas schema, Has tab schema ( 'Table table), columns ~ TableToColumns table, row0 ~ TableToRow table, SListI columns, SListI row1) => QualifiedAlias sch tab -> QueryClause commons schemas params columns -> ConflictClause tab commons schemas params table -> ReturningClause commons schemas params '[tab ::: row0] row1 -> Manipulation commons schemas params row1
- Squeal.PostgreSQL.Manipulation: insertInto_ :: (Has sch schemas schema, Has tab schema ( 'Table table), columns ~ TableToColumns table, row ~ TableToRow table, SListI columns) => QualifiedAlias sch tab -> QueryClause commons schemas params columns -> Manipulation commons schemas params '[]
- Squeal.PostgreSQL.Manipulation: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Manipulation.Manipulation commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance Data.SOP.Constraint.SListI (Squeal.PostgreSQL.Schema.TableToColumns table) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.ConflictClause tab commons schemas params table)
- Squeal.PostgreSQL.Manipulation: instance GHC.Classes.Eq (Squeal.PostgreSQL.Manipulation.Manipulation commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance GHC.Classes.Ord (Squeal.PostgreSQL.Manipulation.Manipulation commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance GHC.Generics.Generic (Squeal.PostgreSQL.Manipulation.Manipulation commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance GHC.Show.Show (Squeal.PostgreSQL.Manipulation.Manipulation commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Query.With Squeal.PostgreSQL.Manipulation.Manipulation
- Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.ConflictAction tab commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Manipulation commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.QueryClause commons schemas params columns)
- Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.ReturningClause commons schemas params from row)
- Squeal.PostgreSQL.Manipulation: instance forall k (expr :: k -> *) (ty :: (Squeal.PostgreSQL.Schema.ColumnConstraint, k)). (forall (x :: k). Squeal.PostgreSQL.Render.RenderSQL (expr x)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Optional expr ty)
- Squeal.PostgreSQL.Manipulation: instance forall kind (constraints :: [(GHC.Types.Symbol, kind)]). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.ConflictTarget constraints)
- Squeal.PostgreSQL.Manipulation: update :: (SListI columns, SListI row1, db ~ (commons :=> schemas), Has sch schemas schema, Has tab schema ( 'Table table), row0 ~ TableToRow table, columns ~ TableToColumns table, All (HasIn columns) subcolumns, AllUnique subcolumns) => QualifiedAlias sch tab -> NP (Aliased (Optional (Expression '[] '[] 'Ungrouped schemas params '[tab ::: row0]))) subcolumns -> Condition '[] commons 'Ungrouped schemas params '[tab ::: row0] -> ReturningClause commons schemas params '[tab ::: row0] row1 -> Manipulation commons schemas params row1
- Squeal.PostgreSQL.Manipulation: update_ :: (SListI columns, db ~ (commons :=> schemas), Has sch schemas schema, Has tab schema ( 'Table table), row ~ TableToRow table, columns ~ TableToColumns table, All (HasIn columns) subcolumns, AllUnique subcolumns) => QualifiedAlias sch tab -> NP (Aliased (Optional (Expression '[] '[] 'Ungrouped schemas params '[tab ::: row]))) subcolumns -> Condition '[] commons 'Ungrouped schemas params '[tab ::: row] -> Manipulation commons schemas params '[]
- Squeal.PostgreSQL.Migration: Migration :: Text -> p schemas0 schemas1 -> p schemas1 schemas0 -> Migration p schemas0 schemas1
- Squeal.PostgreSQL.Migration: Terminally :: trans x0 x1 monad () -> Terminally trans monad x0 x1
- Squeal.PostgreSQL.Migration: [down] :: Migration p schemas0 schemas1 -> p schemas1 schemas0
- Squeal.PostgreSQL.Migration: [name] :: Migration p schemas0 schemas1 -> Text
- Squeal.PostgreSQL.Migration: [runTerminally] :: Terminally trans monad x0 x1 -> trans x0 x1 monad ()
- Squeal.PostgreSQL.Migration: [up] :: Migration p schemas0 schemas1 -> p schemas0 schemas1
- Squeal.PostgreSQL.Migration: class Category p => Migratory p
- Squeal.PostgreSQL.Migration: data Migration p schemas0 schemas1
- Squeal.PostgreSQL.Migration: defaultMain :: Migratory p => ByteString -> AlignedList (Migration p) db0 db1 -> IO ()
- Squeal.PostgreSQL.Migration: instance (Squeal.PostgreSQL.PQ.IndexedMonadTransPQ trans, GHC.Base.Monad monad, forall (x0 :: Squeal.PostgreSQL.Schema.SchemasType) (x1 :: Squeal.PostgreSQL.Schema.SchemasType). (x0 Data.Type.Equality.~ x1) => GHC.Base.Monad (trans x0 x1 monad)) => Control.Category.Category (Squeal.PostgreSQL.Migration.Terminally trans monad)
- Squeal.PostgreSQL.Migration: instance GHC.Generics.Generic Squeal.PostgreSQL.Migration.MigrateCommand
- Squeal.PostgreSQL.Migration: instance GHC.Generics.Generic Squeal.PostgreSQL.Migration.MigrationRow
- Squeal.PostgreSQL.Migration: instance GHC.Show.Show Squeal.PostgreSQL.Migration.MigrateCommand
- Squeal.PostgreSQL.Migration: instance GHC.Show.Show Squeal.PostgreSQL.Migration.MigrationRow
- Squeal.PostgreSQL.Migration: instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Migration.MigrationRow
- Squeal.PostgreSQL.Migration: instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Migration.MigrationRow
- Squeal.PostgreSQL.Migration: instance Squeal.PostgreSQL.Migration.Migratory (Squeal.PostgreSQL.Migration.Terminally Squeal.PostgreSQL.PQ.PQ GHC.Types.IO)
- Squeal.PostgreSQL.Migration: instance Squeal.PostgreSQL.Migration.Migratory Squeal.PostgreSQL.Definition.Definition
- Squeal.PostgreSQL.Migration: instance forall k (p :: k -> k -> *) (schemas0 :: k) (schemas1 :: k). GHC.Generics.Generic (Squeal.PostgreSQL.Migration.Migration p schemas0 schemas1)
- Squeal.PostgreSQL.Migration: instance forall k1 k2 k3 (trans :: k2 -> k3 -> k1 -> * -> *) (monad :: k1) (x0 :: k2) (x1 :: k3). GHC.Generics.Generic (Squeal.PostgreSQL.Migration.Terminally trans monad x0 x1)
- Squeal.PostgreSQL.Migration: migrateDown :: Migratory p => AlignedList (Migration p) schemas0 schemas1 -> PQ schemas1 schemas0 IO ()
- Squeal.PostgreSQL.Migration: migrateUp :: Migratory p => AlignedList (Migration p) schemas0 schemas1 -> PQ schemas0 schemas1 IO ()
- Squeal.PostgreSQL.Migration: newtype Terminally trans monad x0 x1
- Squeal.PostgreSQL.Migration: pureMigration :: Migration Definition schemas0 schemas1 -> Migration (Terminally PQ IO) schemas0 schemas1
- Squeal.PostgreSQL.Migration: terminally :: Functor (trans x0 x1 monad) => trans x0 x1 monad ignore -> Terminally trans monad x0 x1
- Squeal.PostgreSQL.Migration: type MigrationsTable = '["migrations_unique_name" ::: 'Unique '["name"]] :=> '["name" ::: 'NoDef :=> 'NotNull 'PGtext, "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz]
- Squeal.PostgreSQL.PG: Composite :: record -> Composite record
- Squeal.PostgreSQL.PG: Enumerated :: enum -> Enumerated enum
- Squeal.PostgreSQL.PG: FixArray :: arr -> FixArray arr
- Squeal.PostgreSQL.PG: Json :: hask -> Json hask
- Squeal.PostgreSQL.PG: Jsonb :: hask -> Jsonb hask
- Squeal.PostgreSQL.PG: Money :: Int64 -> Money
- Squeal.PostgreSQL.PG: VarArray :: arr -> VarArray arr
- Squeal.PostgreSQL.PG: [cents] :: Money -> Int64
- Squeal.PostgreSQL.PG: [getComposite] :: Composite record -> record
- Squeal.PostgreSQL.PG: [getEnumerated] :: Enumerated enum -> enum
- Squeal.PostgreSQL.PG: [getFixArray] :: FixArray arr -> arr
- Squeal.PostgreSQL.PG: [getJson] :: Json hask -> hask
- Squeal.PostgreSQL.PG: [getJsonb] :: Jsonb hask -> hask
- Squeal.PostgreSQL.PG: [getVarArray] :: VarArray arr -> arr
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq Squeal.PostgreSQL.PG.Money
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.PG.FixArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.PG.VarArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq enum => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Enumerated enum)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Json hask)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Jsonb hask)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Eq record => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Composite record)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord Squeal.PostgreSQL.PG.Money
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.PG.FixArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.PG.VarArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord enum => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Enumerated enum)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Json hask)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Jsonb hask)
- Squeal.PostgreSQL.PG: instance GHC.Classes.Ord record => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Composite record)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Composite record)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Enumerated enum)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.FixArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Json hask)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Jsonb hask)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.VarArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Generics.Generic Squeal.PostgreSQL.PG.Money
- Squeal.PostgreSQL.PG: instance GHC.Read.Read Squeal.PostgreSQL.PG.Money
- Squeal.PostgreSQL.PG: instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.PG.FixArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.PG.VarArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Read.Read enum => GHC.Read.Read (Squeal.PostgreSQL.PG.Enumerated enum)
- Squeal.PostgreSQL.PG: instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.PG.Json hask)
- Squeal.PostgreSQL.PG: instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.PG.Jsonb hask)
- Squeal.PostgreSQL.PG: instance GHC.Read.Read record => GHC.Read.Read (Squeal.PostgreSQL.PG.Composite record)
- Squeal.PostgreSQL.PG: instance GHC.Show.Show Squeal.PostgreSQL.PG.Money
- Squeal.PostgreSQL.PG: instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.PG.FixArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.PG.VarArray arr)
- Squeal.PostgreSQL.PG: instance GHC.Show.Show enum => GHC.Show.Show (Squeal.PostgreSQL.PG.Enumerated enum)
- Squeal.PostgreSQL.PG: instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.PG.Json hask)
- Squeal.PostgreSQL.PG: instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.PG.Jsonb hask)
- Squeal.PostgreSQL.PG: instance GHC.Show.Show record => GHC.Show.Show (Squeal.PostgreSQL.PG.Composite record)
- Squeal.PostgreSQL.PG: newtype Composite record
- Squeal.PostgreSQL.PG: newtype Enumerated enum
- Squeal.PostgreSQL.PG: newtype FixArray arr
- Squeal.PostgreSQL.PG: newtype Json hask
- Squeal.PostgreSQL.PG: newtype Jsonb hask
- Squeal.PostgreSQL.PG: newtype Money
- Squeal.PostgreSQL.PG: newtype VarArray arr
- Squeal.PostgreSQL.PG: type family ConstructorNamesOf (constructors :: [ConstructorInfo]) :: [ConstructorName]
- Squeal.PostgreSQL.PQ: BadResponse :: ExecStatus
- Squeal.PostgreSQL.PQ: CommandOk :: ExecStatus
- Squeal.PostgreSQL.PQ: CopyBoth :: ExecStatus
- Squeal.PostgreSQL.PQ: CopyIn :: ExecStatus
- Squeal.PostgreSQL.PQ: CopyOut :: ExecStatus
- Squeal.PostgreSQL.PQ: EmptyQuery :: ExecStatus
- Squeal.PostgreSQL.PQ: FatalError :: ExecStatus
- Squeal.PostgreSQL.PQ: NonfatalError :: ExecStatus
- Squeal.PostgreSQL.PQ: PQ :: (K Connection schemas0 -> m (K x schemas1)) -> PQ
- Squeal.PostgreSQL.PQ: PQException :: PQState -> SquealException
- Squeal.PostgreSQL.PQ: PQState :: ExecStatus -> Maybe ByteString -> Maybe ByteString -> PQState
- Squeal.PostgreSQL.PQ: ParseException :: Text -> SquealException
- Squeal.PostgreSQL.PQ: ResultException :: Text -> SquealException
- Squeal.PostgreSQL.PQ: SingleTuple :: ExecStatus
- Squeal.PostgreSQL.PQ: TuplesOk :: ExecStatus
- Squeal.PostgreSQL.PQ: [sqlErrorMessage] :: PQState -> Maybe ByteString
- Squeal.PostgreSQL.PQ: [sqlExecStatus] :: PQState -> ExecStatus
- Squeal.PostgreSQL.PQ: [sqlStateCode] :: PQState -> Maybe ByteString
- Squeal.PostgreSQL.PQ: [unPQ] :: PQ -> K Connection schemas0 -> m (K x schemas1)
- Squeal.PostgreSQL.PQ: catchSqueal :: MonadUnliftIO io => io a -> (SquealException -> io a) -> io a
- Squeal.PostgreSQL.PQ: class IndexedMonadTransPQ pq
- Squeal.PostgreSQL.PQ: class Monad pq => MonadPQ schemas pq | pq -> schemas
- Squeal.PostgreSQL.PQ: connectdb :: forall schemas io. MonadIO io => ByteString -> io (K Connection schemas)
- Squeal.PostgreSQL.PQ: data Connection
- Squeal.PostgreSQL.PQ: data ExecStatus
- Squeal.PostgreSQL.PQ: data PQState
- Squeal.PostgreSQL.PQ: data Result
- Squeal.PostgreSQL.PQ: data Row
- Squeal.PostgreSQL.PQ: data SquealException
- Squeal.PostgreSQL.PQ: define :: (IndexedMonadTransPQ pq, MonadIO io) => Definition schemas0 schemas1 -> pq schemas0 schemas1 io ()
- Squeal.PostgreSQL.PQ: evalPQ :: Functor m => PQ schemas0 schemas1 m x -> K Connection schemas0 -> m x
- Squeal.PostgreSQL.PQ: execPQ :: Functor m => PQ schemas0 schemas1 m x -> K Connection schemas0 -> m (K Connection schemas1)
- Squeal.PostgreSQL.PQ: finish :: MonadIO io => K Connection schemas -> io ()
- Squeal.PostgreSQL.PQ: firstRow :: (FromRow columns y, MonadIO io) => K Result columns -> io (Maybe y)
- Squeal.PostgreSQL.PQ: forPrepared :: (MonadPQ schemas pq, ToParams x params, Traversable list) => list x -> Manipulation '[] schemas params ys -> pq (list (K Result ys))
- Squeal.PostgreSQL.PQ: forPrepared_ :: (MonadPQ schemas pq, ToParams x params, Foldable list) => list x -> Manipulation '[] schemas params '[] -> pq ()
- Squeal.PostgreSQL.PQ: getRow :: (FromRow columns y, MonadIO io) => Row -> K Result columns -> io y
- Squeal.PostgreSQL.PQ: getRows :: (FromRow columns y, MonadIO io) => K Result columns -> io [y]
- Squeal.PostgreSQL.PQ: handleSqueal :: MonadUnliftIO io => (SquealException -> io a) -> io a -> io a
- Squeal.PostgreSQL.PQ: instance (Control.Monad.IO.Class.MonadIO io, schemas0 Data.Type.Equality.~ schemas, schemas1 Data.Type.Equality.~ schemas) => Squeal.PostgreSQL.PQ.MonadPQ schemas (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1 io)
- Squeal.PostgreSQL.PQ: instance (Control.Monad.IO.Class.MonadIO m, schema0 Data.Type.Equality.~ schema1) => Control.Monad.IO.Class.MonadIO (Squeal.PostgreSQL.PQ.PQ schema0 schema1 m)
- Squeal.PostgreSQL.PQ: instance (Control.Monad.IO.Unlift.MonadUnliftIO m, schemas0 Data.Type.Equality.~ schemas1) => Control.Monad.IO.Unlift.MonadUnliftIO (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1 m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monad m, schemas0 Data.Type.Equality.~ schemas1) => Control.Monad.Fail.MonadFail (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1 m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monad m, schemas0 Data.Type.Equality.~ schemas1) => GHC.Base.Applicative (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1 m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monad m, schemas0 Data.Type.Equality.~ schemas1) => GHC.Base.Monad (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1 m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.PQ.MonadPQ schemas m) => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.PQ.MonadPQ schemas m) => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.RWS.Strict.RWST r w s m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.PQ.MonadPQ schemas m) => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Writer.Lazy.WriterT w m)
- Squeal.PostgreSQL.PQ: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.PQ.MonadPQ schemas m) => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Writer.Strict.WriterT w m)
- Squeal.PostgreSQL.PQ: instance (schemas0 Data.Type.Equality.~ schemas1) => Control.Monad.Morph.MFunctor (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1)
- Squeal.PostgreSQL.PQ: instance (schemas0 Data.Type.Equality.~ schemas1) => Control.Monad.Morph.MMonad (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1)
- Squeal.PostgreSQL.PQ: instance (schemas0 Data.Type.Equality.~ schemas1) => Control.Monad.Trans.Class.MonadTrans (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1)
- Squeal.PostgreSQL.PQ: instance GHC.Base.Monad m => GHC.Base.Functor (Squeal.PostgreSQL.PQ.PQ schemas0 schemas1 m)
- Squeal.PostgreSQL.PQ: instance GHC.Classes.Eq Squeal.PostgreSQL.PQ.PQState
- Squeal.PostgreSQL.PQ: instance GHC.Classes.Eq Squeal.PostgreSQL.PQ.SquealException
- Squeal.PostgreSQL.PQ: instance GHC.Exception.Type.Exception Squeal.PostgreSQL.PQ.SquealException
- Squeal.PostgreSQL.PQ: instance GHC.Show.Show Squeal.PostgreSQL.PQ.PQState
- Squeal.PostgreSQL.PQ: instance GHC.Show.Show Squeal.PostgreSQL.PQ.SquealException
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.IndexedMonadTransPQ Squeal.PostgreSQL.PQ.PQ
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Cont.ContT r m)
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Except.ExceptT e m)
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Identity.IdentityT m)
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Maybe.MaybeT m)
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.Reader.ReaderT r m)
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.State.Lazy.StateT s m)
- Squeal.PostgreSQL.PQ: instance Squeal.PostgreSQL.PQ.MonadPQ schemas m => Squeal.PostgreSQL.PQ.MonadPQ schemas (Control.Monad.Trans.State.Strict.StateT s m)
- Squeal.PostgreSQL.PQ: liftPQ :: (MonadPQ schemas pq, MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1) => (Connection -> IO a) -> pq a
- Squeal.PostgreSQL.PQ: liftResult :: MonadIO io => (Result -> IO x) -> K Result results -> io x
- Squeal.PostgreSQL.PQ: lowerConnection :: K Connection (schema : schemas) -> K Connection schemas
- Squeal.PostgreSQL.PQ: manipulate :: MonadPQ schemas pq => Manipulation '[] schemas '[] ys -> pq (K Result ys)
- Squeal.PostgreSQL.PQ: manipulateParams :: (MonadPQ schemas pq, MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1) => ToParams x params => Manipulation '[] schemas params ys -> x -> pq (K Result ys)
- Squeal.PostgreSQL.PQ: manipulateParams_ :: (MonadPQ schemas pq, ToParams x params) => Manipulation '[] schemas params '[] -> x -> pq ()
- Squeal.PostgreSQL.PQ: manipulate_ :: MonadPQ schemas pq => Manipulation '[] schemas '[] '[] -> pq ()
- Squeal.PostgreSQL.PQ: newtype PQ (schemas0 :: SchemasType) (schemas1 :: SchemasType) (m :: Type -> Type) (x :: Type)
- Squeal.PostgreSQL.PQ: nextRow :: (FromRow columns y, MonadIO io) => Row -> K Result columns -> Row -> io (Maybe (Row, y))
- Squeal.PostgreSQL.PQ: ntuples :: MonadIO io => K Result columns -> io Row
- Squeal.PostgreSQL.PQ: okResult :: MonadIO io => K Result row -> io ()
- Squeal.PostgreSQL.PQ: pqAndThen :: (IndexedMonadTransPQ pq, Monad m) => (y -> pq schemas1 schemas2 m z) -> (x -> pq schemas0 schemas1 m y) -> x -> pq schemas0 schemas2 m z
- Squeal.PostgreSQL.PQ: pqAp :: (IndexedMonadTransPQ pq, Monad m) => pq schemas0 schemas1 m (x -> y) -> pq schemas1 schemas2 m x -> pq schemas0 schemas2 m y
- Squeal.PostgreSQL.PQ: pqBind :: (IndexedMonadTransPQ pq, Monad m) => (x -> pq schemas1 schemas2 m y) -> pq schemas0 schemas1 m x -> pq schemas0 schemas2 m y
- Squeal.PostgreSQL.PQ: pqJoin :: (IndexedMonadTransPQ pq, Monad m) => pq schemas0 schemas1 m (pq schemas1 schemas2 m y) -> pq schemas0 schemas2 m y
- Squeal.PostgreSQL.PQ: pqThen :: (IndexedMonadTransPQ pq, Monad m) => pq schemas1 schemas2 m y -> pq schemas0 schemas1 m x -> pq schemas0 schemas2 m y
- Squeal.PostgreSQL.PQ: resultErrorCode :: MonadIO io => K Result results -> io (Maybe ByteString)
- Squeal.PostgreSQL.PQ: resultErrorMessage :: MonadIO io => K Result results -> io (Maybe ByteString)
- Squeal.PostgreSQL.PQ: resultStatus :: MonadIO io => K Result results -> io ExecStatus
- Squeal.PostgreSQL.PQ: runPQ :: Functor m => PQ schemas0 schemas1 m x -> K Connection schemas0 -> m (x, K Connection schemas1)
- Squeal.PostgreSQL.PQ: runQuery :: MonadPQ schemas pq => Query '[] '[] schemas '[] ys -> pq (K Result ys)
- Squeal.PostgreSQL.PQ: runQueryParams :: (MonadPQ schemas pq, ToParams x params) => Query '[] '[] schemas params ys -> x -> pq (K Result ys)
- Squeal.PostgreSQL.PQ: traversePrepared :: (MonadPQ schemas pq, MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1) => (ToParams x params, Traversable list) => Manipulation '[] schemas params ys -> list x -> pq (list (K Result ys))
- Squeal.PostgreSQL.PQ: traversePrepared_ :: (MonadPQ schemas pq, MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1) => (ToParams x params, Foldable list) => Manipulation '[] schemas params '[] -> list x -> pq ()
- Squeal.PostgreSQL.PQ: trySqueal :: MonadUnliftIO io => io a -> io (Either SquealException a)
- Squeal.PostgreSQL.PQ: withConnection :: forall schemas0 schemas1 io x. MonadUnliftIO io => ByteString -> PQ schemas0 schemas1 io x -> io x
- Squeal.PostgreSQL.Pool: createConnectionPool :: MonadUnliftIO io => ByteString -> Int -> NominalDiffTime -> Int -> io (Pool (K Connection schemas))
- Squeal.PostgreSQL.Pool: destroyConnectionPool :: MonadUnliftIO io => Pool (K Connection schemas) -> io ()
- Squeal.PostgreSQL.Pool: type Pool = Pool
- Squeal.PostgreSQL.Pool: usingConnectionPool :: MonadUnliftIO io => Pool (K Connection schemas) -> PQ schemas schemas io x -> io x
- Squeal.PostgreSQL.Query: TableExpression :: FromClause outer commons schemas params from -> [Condition outer commons 'Ungrouped schemas params from] -> GroupByClause grp from -> HavingClause outer commons grp schemas params from -> [SortExpression outer commons grp schemas params from] -> [Word64] -> [Word64] -> TableExpression
- Squeal.PostgreSQL.Query: UnsafeFromClause :: ByteString -> FromClause outer commons schemas params from
- Squeal.PostgreSQL.Query: [Also] :: Selection outer commons grp schemas params from right -> Selection outer commons grp schemas params from left -> Selection outer commons grp schemas params from (Join left right)
- Squeal.PostgreSQL.Query: [By1] :: (HasUnique table from columns, Has column columns ty) => Alias column -> By from '(table, column)
- Squeal.PostgreSQL.Query: [By2] :: (Has table from columns, Has column columns ty) => Alias table -> Alias column -> By from '(table, column)
- Squeal.PostgreSQL.Query: [CommonTableExpression] :: Aliased (statement commons schemas params) (cte ::: common) -> CommonTableExpression statement schemas params commons ((cte ::: common) : commons)
- Squeal.PostgreSQL.Query: [DotStar] :: Has tab from row => Alias tab -> Selection outer commons 'Ungrouped schemas params from row
- Squeal.PostgreSQL.Query: [Group] :: SListI bys => NP (By from) bys -> GroupByClause ( 'Grouped bys) from
- Squeal.PostgreSQL.Query: [Having] :: [Condition outer commons ( 'Grouped bys) schemas params from] -> HavingClause outer commons ( 'Grouped bys) schemas params from
- Squeal.PostgreSQL.Query: [List] :: SListI row => NP (Aliased (Expression outer commons grp schemas params from)) row -> Selection outer commons grp schemas params from row
- Squeal.PostgreSQL.Query: [NoGroups] :: GroupByClause 'Ungrouped from
- Squeal.PostgreSQL.Query: [NoHaving] :: HavingClause outer commons 'Ungrouped schemas params from
- Squeal.PostgreSQL.Query: [Over] :: SListI row => NP (Aliased (WindowFunction outer commons grp schemas params from)) row -> WindowDefinition outer commons grp schemas params from -> Selection outer commons grp schemas params from row
- Squeal.PostgreSQL.Query: [Star] :: HasUnique tab from row => Selection outer commons 'Ungrouped schemas params from row
- Squeal.PostgreSQL.Query: [fromClause] :: TableExpression -> FromClause outer commons schemas params from
- Squeal.PostgreSQL.Query: [groupByClause] :: TableExpression -> GroupByClause grp from
- Squeal.PostgreSQL.Query: [havingClause] :: TableExpression -> HavingClause outer commons grp schemas params from
- Squeal.PostgreSQL.Query: [limitClause] :: TableExpression -> [Word64]
- Squeal.PostgreSQL.Query: [offsetClause] :: TableExpression -> [Word64]
- Squeal.PostgreSQL.Query: [orderByClause] :: TableExpression -> [SortExpression outer commons grp schemas params from]
- Squeal.PostgreSQL.Query: [renderFromClause] :: FromClause outer commons schemas params from -> ByteString
- Squeal.PostgreSQL.Query: [whereClause] :: TableExpression -> [Condition outer commons 'Ungrouped schemas params from]
- Squeal.PostgreSQL.Query: class With statement
- Squeal.PostgreSQL.Query: common :: Has cte commons common => Aliased Alias (alias ::: cte) -> FromClause outer commons schemas params '[alias ::: common]
- Squeal.PostgreSQL.Query: crossJoin :: FromClause outer commons schemas params right -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join left right)
- Squeal.PostgreSQL.Query: data By (from :: FromType) (by :: (Symbol, Symbol))
- Squeal.PostgreSQL.Query: data CommonTableExpression statement (schemas :: SchemasType) (params :: [NullityType]) (commons0 :: FromType) (commons1 :: FromType)
- Squeal.PostgreSQL.Query: data GroupByClause grp from
- Squeal.PostgreSQL.Query: data HavingClause outer commons grp schemas params from
- Squeal.PostgreSQL.Query: data Selection outer commons grp schemas params from row
- Squeal.PostgreSQL.Query: data TableExpression (outer :: FromType) (commons :: FromType) (grp :: Grouping) (schemas :: SchemasType) (params :: [NullityType]) (from :: FromType)
- Squeal.PostgreSQL.Query: from :: FromClause outer commons schemas params from -> TableExpression outer commons 'Ungrouped schemas params from
- Squeal.PostgreSQL.Query: fullOuterJoin :: FromClause outer commons schemas params right -> Condition outer commons 'Ungrouped schemas params (Join left right) -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join (NullifyFrom left) (NullifyFrom right))
- Squeal.PostgreSQL.Query: groupBy :: SListI bys => NP (By from) bys -> TableExpression outer commons 'Ungrouped schemas params from -> TableExpression outer commons ( 'Grouped bys) schemas params from
- Squeal.PostgreSQL.Query: having :: Condition outer commons ( 'Grouped bys) schemas params from -> TableExpression outer commons ( 'Grouped bys) schemas params from -> TableExpression outer commons ( 'Grouped bys) schemas params from
- Squeal.PostgreSQL.Query: innerJoin :: FromClause outer commons schemas params right -> Condition outer commons 'Ungrouped schemas params (Join left right) -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join left right)
- Squeal.PostgreSQL.Query: instance (GHC.TypeLits.KnownSymbol col, row Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => Squeal.PostgreSQL.Alias.Aliasable col (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) (Squeal.PostgreSQL.Query.Selection outer commons grp schemas params from row)
- Squeal.PostgreSQL.Query: instance (GHC.TypeLits.KnownSymbol cte, commons1 Data.Type.Equality.~ ((cte Squeal.PostgreSQL.Alias.::: common) : commons)) => Squeal.PostgreSQL.Alias.Aliasable cte (statement commons schemas params common) (Squeal.PostgreSQL.List.AlignedList (Squeal.PostgreSQL.Query.CommonTableExpression statement schemas params) commons commons1)
- Squeal.PostgreSQL.Query: instance (GHC.TypeLits.KnownSymbol cte, commons1 Data.Type.Equality.~ ((cte Squeal.PostgreSQL.Alias.::: common) : commons)) => Squeal.PostgreSQL.Alias.Aliasable cte (statement commons schemas params common) (Squeal.PostgreSQL.Query.CommonTableExpression statement schemas params commons commons1)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.Has rel rels cols, Squeal.PostgreSQL.Alias.Has col cols ty, by Data.Type.Equality.~ '(rel, col)) => Squeal.PostgreSQL.Alias.IsQualified rel col (Squeal.PostgreSQL.Query.By rels by)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.Has rel rels cols, Squeal.PostgreSQL.Alias.Has col cols ty, bys Data.Type.Equality.~ '[ '(rel, col)]) => Squeal.PostgreSQL.Alias.IsQualified rel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Query.By rels) bys)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row0, Squeal.PostgreSQL.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => Squeal.PostgreSQL.Alias.IsQualified tab col (Squeal.PostgreSQL.Query.Selection outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from row1)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.Has tab (Squeal.PostgreSQL.List.Join outer from) row0, Squeal.PostgreSQL.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty], Squeal.PostgreSQL.Alias.GroupedBy tab col bys) => Squeal.PostgreSQL.Alias.IsQualified tab col (Squeal.PostgreSQL.Query.Selection outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from row1)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.HasUnique rel rels cols, Squeal.PostgreSQL.Alias.Has col cols ty, by Data.Type.Equality.~ '(rel, col)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.By rels by)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.HasUnique rel rels cols, Squeal.PostgreSQL.Alias.Has col cols ty, bys Data.Type.Equality.~ '[ '(rel, col)]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Query.By rels) bys)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row0, Squeal.PostgreSQL.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Selection outer commons 'Squeal.PostgreSQL.Alias.Ungrouped schemas params from row1)
- Squeal.PostgreSQL.Query: instance (Squeal.PostgreSQL.Alias.HasUnique tab (Squeal.PostgreSQL.List.Join outer from) row0, Squeal.PostgreSQL.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Alias.::: ty], Squeal.PostgreSQL.Alias.GroupedBy tab col bys) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Selection outer commons ('Squeal.PostgreSQL.Alias.Grouped bys) schemas params from row1)
- Squeal.PostgreSQL.Query: instance (forall (c :: Squeal.PostgreSQL.Schema.FromType) (s :: Squeal.PostgreSQL.Schema.SchemasType) (p :: [Squeal.PostgreSQL.Schema.NullityType]) (r :: Squeal.PostgreSQL.Schema.RowType). Squeal.PostgreSQL.Render.RenderSQL (statement c s p r)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.CommonTableExpression statement schemas params commons0 commons1)
- Squeal.PostgreSQL.Query: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
- Squeal.PostgreSQL.Query: instance Data.String.IsString (Squeal.PostgreSQL.Query.Selection outer commons grp schemas params from '["fromOnly" Squeal.PostgreSQL.Alias.::: 'Squeal.PostgreSQL.Schema.NotNull 'Squeal.PostgreSQL.Schema.PGtext])
- Squeal.PostgreSQL.Query: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.By from by)
- Squeal.PostgreSQL.Query: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
- Squeal.PostgreSQL.Query: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.By from by)
- Squeal.PostgreSQL.Query: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
- Squeal.PostgreSQL.Query: instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
- Squeal.PostgreSQL.Query: instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.TableExpression outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance GHC.Show.Show (Squeal.PostgreSQL.Query.By from by)
- Squeal.PostgreSQL.Query: instance GHC.Show.Show (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance GHC.Show.Show (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Expression.Sort.OrderBy Squeal.PostgreSQL.Query.TableExpression
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.List.Additional (Squeal.PostgreSQL.Query.Selection outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Query.With (Squeal.PostgreSQL.Query.Query outer)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.By from by)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.GroupByClause grp from)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Selection outer commons grp schemas params from row)
- Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.TableExpression outer commons grp schemas params from)
- Squeal.PostgreSQL.Query: instance forall a k1 k2 k3 k4 (outer :: k4) (commons :: k3) (schemas :: k2) (params :: k1). Squeal.PostgreSQL.List.Additional (Squeal.PostgreSQL.Query.FromClause outer commons schemas params)
- Squeal.PostgreSQL.Query: instance forall k1 (outer :: k1) k2 (commons :: k2) k3 (schemas :: k3) k4 (params :: k4) k5 (from :: k5). Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.FromClause outer commons schemas params from)
- Squeal.PostgreSQL.Query: instance forall k1 (outer :: k1) k2 (commons :: k2) k3 (schemas :: k3) k4 (params :: k4) k5 (from :: k5). GHC.Classes.Eq (Squeal.PostgreSQL.Query.FromClause outer commons schemas params from)
- Squeal.PostgreSQL.Query: instance forall k1 (outer :: k1) k2 (commons :: k2) k3 (schemas :: k3) k4 (params :: k4) k5 (from :: k5). GHC.Classes.Ord (Squeal.PostgreSQL.Query.FromClause outer commons schemas params from)
- Squeal.PostgreSQL.Query: instance forall k1 (outer :: k1) k2 (commons :: k2) k3 (schemas :: k3) k4 (params :: k4) k5 (from :: k5). GHC.Generics.Generic (Squeal.PostgreSQL.Query.FromClause outer commons schemas params from)
- Squeal.PostgreSQL.Query: instance forall k1 (outer :: k1) k2 (commons :: k2) k3 (schemas :: k3) k4 (params :: k4) k5 (from :: k5). GHC.Show.Show (Squeal.PostgreSQL.Query.FromClause outer commons schemas params from)
- Squeal.PostgreSQL.Query: instance forall k1 k2 k3 k4 k5 (outer :: k5) (commons :: k4) (schemas :: k3) (params :: k2) (from :: k1). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.FromClause outer commons schemas params from)
- Squeal.PostgreSQL.Query: leftOuterJoin :: FromClause outer commons schemas params right -> Condition outer commons 'Ungrouped schemas params (Join left right) -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join left (NullifyFrom right))
- Squeal.PostgreSQL.Query: limit :: Word64 -> TableExpression outer commons grp schemas params from -> TableExpression outer commons grp schemas params from
- Squeal.PostgreSQL.Query: newtype FromClause outer commons schemas params from
- Squeal.PostgreSQL.Query: offset :: Word64 -> TableExpression outer commons grp schemas params from -> TableExpression outer commons grp schemas params from
- Squeal.PostgreSQL.Query: rightOuterJoin :: FromClause outer commons schemas params right -> Condition outer commons 'Ungrouped schemas params (Join left right) -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join (NullifyFrom left) right)
- Squeal.PostgreSQL.Query: select :: (SListI row, row ~ (x : xs)) => Selection outer commons grp schemas params from row -> TableExpression outer commons grp schemas params from -> Query outer commons schemas params row
- Squeal.PostgreSQL.Query: selectDistinct :: (SListI columns, columns ~ (col : cols)) => Selection outer commons 'Ungrouped schemas params from columns -> TableExpression outer commons 'Ungrouped schemas params from -> Query outer commons schemas params columns
- Squeal.PostgreSQL.Query: selectDistinct_ :: (SListI columns, columns ~ (col : cols)) => NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns -> TableExpression outer commons 'Ungrouped schemas params from -> Query outer commons schemas params columns
- Squeal.PostgreSQL.Query: select_ :: (SListI row, row ~ (x : xs)) => NP (Aliased (Expression outer commons grp schemas params from)) row -> TableExpression outer commons grp schemas params from -> Query outer commons schemas params row
- Squeal.PostgreSQL.Query: subquery :: Aliased (Query outer commons schemas params) query -> FromClause outer commons schemas params '[query]
- Squeal.PostgreSQL.Query: table :: (Has sch schemas schema, Has tab schema ( 'Table table)) => Aliased (QualifiedAlias sch) (alias ::: tab) -> FromClause outer commons schemas params '[alias ::: TableToRow table]
- Squeal.PostgreSQL.Query: values :: SListI cols => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[])) cols -> [NP (Aliased (Expression outer commons 'Ungrouped schemas params '[])) cols] -> Query outer commons schemas params cols
- Squeal.PostgreSQL.Query: values_ :: SListI cols => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[])) cols -> Query outer commons schemas params cols
- Squeal.PostgreSQL.Query: view :: (Has sch schemas schema, Has vw schema ( 'View view)) => Aliased (QualifiedAlias sch) (alias ::: vw) -> FromClause outer commons schemas params '[alias ::: view]
- Squeal.PostgreSQL.Query: where_ :: Condition outer commons 'Ungrouped schemas params from -> TableExpression outer commons grp schemas params from -> TableExpression outer commons grp schemas params from
- Squeal.PostgreSQL.Query: with :: With statement => AlignedList (CommonTableExpression statement schemas params) commons0 commons1 -> statement commons1 schemas params row -> statement commons0 schemas params row
- Squeal.PostgreSQL.Query: withRecursive :: Aliased (Query outer (recursive : commons) schemas params) recursive -> Query outer (recursive : commons) schemas params row -> Query outer commons schemas params row
- Squeal.PostgreSQL.Schema: Check :: [Symbol] -> TableConstraint
- Squeal.PostgreSQL.Schema: Def :: ColumnConstraint
- Squeal.PostgreSQL.Schema: ForeignKey :: [Symbol] -> Symbol -> [Symbol] -> TableConstraint
- Squeal.PostgreSQL.Schema: NoDef :: ColumnConstraint
- Squeal.PostgreSQL.Schema: NotNull :: PGType -> NullityType
- Squeal.PostgreSQL.Schema: Null :: PGType -> NullityType
- Squeal.PostgreSQL.Schema: PGbool :: PGType
- Squeal.PostgreSQL.Schema: PGbytea :: PGType
- Squeal.PostgreSQL.Schema: PGchar :: Nat -> PGType
- Squeal.PostgreSQL.Schema: PGcomposite :: RowType -> PGType
- Squeal.PostgreSQL.Schema: PGdate :: PGType
- Squeal.PostgreSQL.Schema: PGenum :: [Symbol] -> PGType
- Squeal.PostgreSQL.Schema: PGfixarray :: [Nat] -> NullityType -> PGType
- Squeal.PostgreSQL.Schema: PGfloat4 :: PGType
- Squeal.PostgreSQL.Schema: PGfloat8 :: PGType
- Squeal.PostgreSQL.Schema: PGinet :: PGType
- Squeal.PostgreSQL.Schema: PGint2 :: PGType
- Squeal.PostgreSQL.Schema: PGint4 :: PGType
- Squeal.PostgreSQL.Schema: PGint8 :: PGType
- Squeal.PostgreSQL.Schema: PGinterval :: PGType
- Squeal.PostgreSQL.Schema: PGjson :: PGType
- Squeal.PostgreSQL.Schema: PGjsonb :: PGType
- Squeal.PostgreSQL.Schema: PGlabel :: PGlabel
- Squeal.PostgreSQL.Schema: PGmoney :: PGType
- Squeal.PostgreSQL.Schema: PGnumeric :: PGType
- Squeal.PostgreSQL.Schema: PGtext :: PGType
- Squeal.PostgreSQL.Schema: PGtime :: PGType
- Squeal.PostgreSQL.Schema: PGtimestamp :: PGType
- Squeal.PostgreSQL.Schema: PGtimestamptz :: PGType
- Squeal.PostgreSQL.Schema: PGtimetz :: PGType
- Squeal.PostgreSQL.Schema: PGtsquery :: PGType
- Squeal.PostgreSQL.Schema: PGtsvector :: PGType
- Squeal.PostgreSQL.Schema: PGuuid :: PGType
- Squeal.PostgreSQL.Schema: PGvararray :: NullityType -> PGType
- Squeal.PostgreSQL.Schema: PGvarchar :: Nat -> PGType
- Squeal.PostgreSQL.Schema: PrimaryKey :: [Symbol] -> TableConstraint
- Squeal.PostgreSQL.Schema: Table :: TableType -> SchemumType
- Squeal.PostgreSQL.Schema: Typedef :: PGType -> SchemumType
- Squeal.PostgreSQL.Schema: Unique :: [Symbol] -> TableConstraint
- Squeal.PostgreSQL.Schema: UnsafePGType :: Symbol -> PGType
- Squeal.PostgreSQL.Schema: View :: RowType -> SchemumType
- Squeal.PostgreSQL.Schema: class AllUnique (xs :: [(Symbol, a)])
- Squeal.PostgreSQL.Schema: class IsNotElem x isElem
- Squeal.PostgreSQL.Schema: class IsPGlabel (label :: Symbol) expr
- Squeal.PostgreSQL.Schema: class SamePGType (ty0 :: (Symbol, ColumnType)) (ty1 :: (Symbol, ColumnType))
- Squeal.PostgreSQL.Schema: data ColumnConstraint
- Squeal.PostgreSQL.Schema: data NullityType
- Squeal.PostgreSQL.Schema: data PGType
- Squeal.PostgreSQL.Schema: data PGlabel (label :: Symbol)
- Squeal.PostgreSQL.Schema: data SchemumType
- Squeal.PostgreSQL.Schema: data TableConstraint
- Squeal.PostgreSQL.Schema: infixr 7 :=>
- Squeal.PostgreSQL.Schema: instance (label Data.Type.Equality.~ label1) => Squeal.PostgreSQL.Schema.IsPGlabel label (Squeal.PostgreSQL.Schema.PGlabel label1)
- Squeal.PostgreSQL.Schema: instance (labels Data.Type.Equality.~ '[label]) => Squeal.PostgreSQL.Schema.IsPGlabel label (Data.SOP.NP.NP Squeal.PostgreSQL.Schema.PGlabel labels)
- Squeal.PostgreSQL.Schema: instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol labels => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Schema.PGlabel labels)
- Squeal.PostgreSQL.Schema: instance GHC.TypeLits.KnownSymbol label => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Schema.PGlabel label)
- Squeal.PostgreSQL.Schema: instance Squeal.PostgreSQL.Schema.AllUnique '[]
- Squeal.PostgreSQL.Schema: instance forall a (x :: (GHC.Types.Symbol, a)) (xs :: [(GHC.Types.Symbol, a)]). (Squeal.PostgreSQL.Schema.IsNotElem x (Squeal.PostgreSQL.List.Elem x xs), Squeal.PostgreSQL.Schema.AllUnique xs) => Squeal.PostgreSQL.Schema.AllUnique (x : xs)
- Squeal.PostgreSQL.Schema: instance forall k (ty0 :: k) (ty1 :: k) (alias0 :: GHC.Types.Symbol) (def0 :: Squeal.PostgreSQL.Schema.ColumnConstraint) (nullity0 :: k -> Squeal.PostgreSQL.Schema.NullityType) (alias1 :: GHC.Types.Symbol) (def1 :: Squeal.PostgreSQL.Schema.ColumnConstraint) (nullity1 :: k -> Squeal.PostgreSQL.Schema.NullityType). (ty0 Data.Type.Equality.~ ty1) => Squeal.PostgreSQL.Schema.SamePGType (alias0 Squeal.PostgreSQL.Alias.::: (def0 Squeal.PostgreSQL.Schema.:=> nullity0 ty0)) (alias1 Squeal.PostgreSQL.Alias.::: (def1 Squeal.PostgreSQL.Schema.:=> nullity1 ty1))
- Squeal.PostgreSQL.Schema: instance forall k (x :: k). Squeal.PostgreSQL.Schema.IsNotElem x 'GHC.Types.False
- Squeal.PostgreSQL.Schema: instance forall k1 k2 (alias :: k2) (a :: k1). (TypeError ...) => Squeal.PostgreSQL.Schema.IsNotElem '(alias, a) 'GHC.Types.True
- Squeal.PostgreSQL.Schema: label :: IsPGlabel label expr => expr
- Squeal.PostgreSQL.Schema: type (:=>) constraint ty = '(constraint, ty)
- Squeal.PostgreSQL.Schema: type ColumnType = (ColumnConstraint, NullityType)
- Squeal.PostgreSQL.Schema: type ColumnsType = [(Symbol, ColumnType)]
- Squeal.PostgreSQL.Schema: type FromType = [(Symbol, RowType)]
- Squeal.PostgreSQL.Schema: type PGFloating = '[ 'PGfloat4, 'PGfloat8, 'PGnumeric]
- Squeal.PostgreSQL.Schema: type PGIntegral = '[ 'PGint2, 'PGint4, 'PGint8]
- Squeal.PostgreSQL.Schema: type PGJsonKey = '[ 'PGint2, 'PGint4, 'PGtext]
- Squeal.PostgreSQL.Schema: type PGJsonType = '[ 'PGjson, 'PGjsonb]
- Squeal.PostgreSQL.Schema: type PGNum = '[ 'PGint2, 'PGint4, 'PGint8, 'PGnumeric, 'PGfloat4, 'PGfloat8]
- Squeal.PostgreSQL.Schema: type RowType = [(Symbol, NullityType)]
- Squeal.PostgreSQL.Schema: type SchemaType = [(Symbol, SchemumType)]
- Squeal.PostgreSQL.Schema: type SchemasType = [(Symbol, SchemaType)]
- Squeal.PostgreSQL.Schema: type TableConstraints = [(Symbol, TableConstraint)]
- Squeal.PostgreSQL.Schema: type TableType = (TableConstraints, ColumnsType)
- Squeal.PostgreSQL.Schema: type family TableToRow (table :: TableType) :: RowType
- Squeal.PostgreSQL.Transaction: Deferrable :: DeferrableMode
- Squeal.PostgreSQL.Transaction: NotDeferrable :: DeferrableMode
- Squeal.PostgreSQL.Transaction: ReadCommitted :: IsolationLevel
- Squeal.PostgreSQL.Transaction: ReadOnly :: AccessMode
- Squeal.PostgreSQL.Transaction: ReadUncommitted :: IsolationLevel
- Squeal.PostgreSQL.Transaction: ReadWrite :: AccessMode
- Squeal.PostgreSQL.Transaction: RepeatableRead :: IsolationLevel
- Squeal.PostgreSQL.Transaction: Serializable :: IsolationLevel
- Squeal.PostgreSQL.Transaction: TransactionMode :: IsolationLevel -> AccessMode -> DeferrableMode -> TransactionMode
- Squeal.PostgreSQL.Transaction: [accessMode] :: TransactionMode -> AccessMode
- Squeal.PostgreSQL.Transaction: [deferrableMode] :: TransactionMode -> DeferrableMode
- Squeal.PostgreSQL.Transaction: [isolationLevel] :: TransactionMode -> IsolationLevel
- Squeal.PostgreSQL.Transaction: begin :: TransactionMode -> Manipulation_ schemas () ()
- Squeal.PostgreSQL.Transaction: commit :: Manipulation_ schemas () ()
- Squeal.PostgreSQL.Transaction: data AccessMode
- Squeal.PostgreSQL.Transaction: data DeferrableMode
- Squeal.PostgreSQL.Transaction: data IsolationLevel
- Squeal.PostgreSQL.Transaction: data TransactionMode
- Squeal.PostgreSQL.Transaction: defaultMode :: TransactionMode
- Squeal.PostgreSQL.Transaction: ephemerally :: (MonadUnliftIO tx, MonadPQ schemas tx) => TransactionMode -> tx x -> tx x
- Squeal.PostgreSQL.Transaction: ephemerally_ :: (MonadUnliftIO tx, MonadPQ schemas tx) => tx x -> tx x
- Squeal.PostgreSQL.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Transaction.AccessMode
- Squeal.PostgreSQL.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Transaction.DeferrableMode
- Squeal.PostgreSQL.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Transaction.IsolationLevel
- Squeal.PostgreSQL.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Transaction.TransactionMode
- Squeal.PostgreSQL.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Transaction.AccessMode
- Squeal.PostgreSQL.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Transaction.DeferrableMode
- Squeal.PostgreSQL.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Transaction.IsolationLevel
- Squeal.PostgreSQL.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Transaction.TransactionMode
- Squeal.PostgreSQL.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Transaction.AccessMode
- Squeal.PostgreSQL.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Transaction.DeferrableMode
- Squeal.PostgreSQL.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Transaction.IsolationLevel
- Squeal.PostgreSQL.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Transaction.TransactionMode
- Squeal.PostgreSQL.Transaction: longRunningMode :: TransactionMode
- Squeal.PostgreSQL.Transaction: rollback :: Manipulation_ schemas () ()
- Squeal.PostgreSQL.Transaction: transactionally :: (MonadUnliftIO tx, MonadPQ schemas tx) => TransactionMode -> tx x -> tx x
- Squeal.PostgreSQL.Transaction: transactionallyRetry :: (MonadUnliftIO tx, MonadPQ schemas tx) => TransactionMode -> tx x -> tx x
- Squeal.PostgreSQL.Transaction: transactionally_ :: (MonadUnliftIO tx, MonadPQ schemas tx) => tx x -> tx x
+ Squeal.PostgreSQL.Definition: instance (db0 Data.Type.Equality.~ db1) => GHC.Base.Monoid (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance (db0 Data.Type.Equality.~ db1) => GHC.Base.Semigroup (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Definition db0 db1)
+ Squeal.PostgreSQL.Definition: manipulation_ :: Manipulation '[] db '[] '[] -> Definition db db
+ Squeal.PostgreSQL.Definition.Constraint: OnDeleteCascade :: OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: OnDeleteNoAction :: OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: OnDeleteRestrict :: OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: OnUpdateCascade :: OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: OnUpdateNoAction :: OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: OnUpdateRestrict :: OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: UnsafeTableConstraintExpression :: ByteString -> TableConstraintExpression
+ Squeal.PostgreSQL.Definition.Constraint: [renderTableConstraintExpression] :: TableConstraintExpression -> ByteString
+ Squeal.PostgreSQL.Definition.Constraint: check :: (Has sch db schema, Has tab schema ( 'Table table), HasAll aliases (TableToRow table) subcolumns) => NP Alias aliases -> (forall t. Condition 'Ungrouped '[] '[] db '[] '[t ::: subcolumns]) -> TableConstraintExpression sch tab db ( 'Check aliases)
+ Squeal.PostgreSQL.Definition.Constraint: data OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: data OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: foreignKey :: ForeignKeyed db sch schema child parent table reftable columns refcolumns constraints cols reftys tys => NP Alias columns -> Alias parent -> NP Alias refcolumns -> OnDeleteClause -> OnUpdateClause -> TableConstraintExpression sch child db ( 'ForeignKey columns parent refcolumns)
+ Squeal.PostgreSQL.Definition.Constraint: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
+ Squeal.PostgreSQL.Definition.Constraint: instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Show.Show Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: instance GHC.Show.Show Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
+ Squeal.PostgreSQL.Definition.Constraint: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
+ Squeal.PostgreSQL.Definition.Constraint: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
+ Squeal.PostgreSQL.Definition.Constraint: newtype TableConstraintExpression (sch :: Symbol) (tab :: Symbol) (db :: SchemasType) (constraint :: TableConstraint)
+ Squeal.PostgreSQL.Definition.Constraint: primaryKey :: (Has sch db schema, Has tab schema ( 'Table table), HasAll aliases (TableToColumns table) subcolumns, AllNotNull subcolumns) => NP Alias aliases -> TableConstraintExpression sch tab db ( 'PrimaryKey aliases)
+ Squeal.PostgreSQL.Definition.Constraint: type ForeignKeyed db sch schema child parent table reftable columns refcolumns constraints cols reftys tys = (Has sch db schema, Has child schema ( 'Table table), Has parent schema ( 'Table reftable), HasAll columns (TableToColumns table) tys, reftable ~ (constraints :=> cols), HasAll refcolumns cols reftys, AllZip SamePGType tys reftys, Uniquely refcolumns constraints)
+ Squeal.PostgreSQL.Definition.Constraint: unique :: (Has sch db schema, Has tab schema ( 'Table table), HasAll aliases (TableToRow table) subcolumns) => NP Alias aliases -> TableConstraintExpression sch tab db ( 'Unique aliases)
+ Squeal.PostgreSQL.Definition.Function: UnsafeFunctionDefinition :: ByteString -> FunctionDefinition db args ret
+ Squeal.PostgreSQL.Definition.Function: [renderFunctionDefinition] :: FunctionDefinition db args ret -> ByteString
+ Squeal.PostgreSQL.Definition.Function: createFunction :: (Has sch db schema, KnownSymbol fun, SListI args) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> TypeExpression db ret -> FunctionDefinition db args ( 'Returns ret) -> Definition db (Alter sch (Create fun ( 'Function (args :=> 'Returns ret)) schema) db)
+ Squeal.PostgreSQL.Definition.Function: createOrReplaceFunction :: (Has sch db schema, KnownSymbol fun, SListI args) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> TypeExpression db ret -> FunctionDefinition db args ( 'Returns ret) -> Definition db (Alter sch (CreateOrReplace fun ( 'Function (args :=> 'Returns ret)) schema) db)
+ Squeal.PostgreSQL.Definition.Function: createOrReplaceSetFunction :: (Has sch db schema, KnownSymbol fun, SListI args, SListI rets) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> NP (Aliased (TypeExpression db)) rets -> FunctionDefinition db args ( 'ReturnsTable rets) -> Definition db (Alter sch (CreateOrReplace fun ( 'Function (args :=> 'ReturnsTable rets)) schema) db)
+ Squeal.PostgreSQL.Definition.Function: createSetFunction :: (Has sch db schema, KnownSymbol fun, SListI args, SListI rets) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> NP (Aliased (TypeExpression db)) rets -> FunctionDefinition db args ( 'ReturnsTable rets) -> Definition db (Alter sch (Create fun ( 'Function (args :=> 'ReturnsTable rets)) schema) db)
+ Squeal.PostgreSQL.Definition.Function: dropFunction :: (Has sch db schema, KnownSymbol fun) => QualifiedAlias sch fun -> Definition db (Alter sch (DropSchemum fun 'Function schema) db)
+ Squeal.PostgreSQL.Definition.Function: dropFunctionIfExists :: (Has sch db schema, KnownSymbol fun) => QualifiedAlias sch fun -> Definition db (Alter sch (DropSchemumIfExists fun 'Function schema) db)
+ Squeal.PostgreSQL.Definition.Function: instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
+ Squeal.PostgreSQL.Definition.Function: instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
+ Squeal.PostgreSQL.Definition.Function: instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
+ Squeal.PostgreSQL.Definition.Function: instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). GHC.Show.Show (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
+ Squeal.PostgreSQL.Definition.Function: instance forall k1 k2 k3 (db :: k3) (args :: k2) (ret :: k1). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
+ Squeal.PostgreSQL.Definition.Function: languageSqlExpr :: Expression 'Ungrouped '[] '[] db args '[] ret -> FunctionDefinition db args ( 'Returns ret)
+ Squeal.PostgreSQL.Definition.Function: languageSqlQuery :: Query '[] '[] db args rets -> FunctionDefinition db args ( 'ReturnsTable rets)
+ Squeal.PostgreSQL.Definition.Function: newtype FunctionDefinition db args ret
+ Squeal.PostgreSQL.Definition.Index: UnsafeIndexMethod :: ByteString -> IndexMethod ty
+ Squeal.PostgreSQL.Definition.Index: [renderIndexMethod] :: IndexMethod ty -> ByteString
+ Squeal.PostgreSQL.Definition.Index: brin :: IndexMethod 'Brin
+ Squeal.PostgreSQL.Definition.Index: btree :: IndexMethod 'Btree
+ Squeal.PostgreSQL.Definition.Index: createIndex :: (Has sch db schema, Has tab schema ( 'Table table), KnownSymbol ix) => Alias ix -> QualifiedAlias sch tab -> IndexMethod method -> [SortExpression 'Ungrouped '[] '[] db '[] '[tab ::: TableToRow table]] -> Definition db (Alter sch (Create ix ( 'Index method) schema) db)
+ Squeal.PostgreSQL.Definition.Index: createIndexIfNotExists :: (Has sch db schema, Has tab schema ( 'Table table), KnownSymbol ix) => Alias ix -> QualifiedAlias sch tab -> IndexMethod method -> [SortExpression 'Ungrouped '[] '[] db '[] '[tab ::: TableToRow table]] -> Definition db (Alter sch (CreateIfNotExists ix ( 'Index method) schema) db)
+ Squeal.PostgreSQL.Definition.Index: dropIndex :: (Has sch db schema, KnownSymbol ix) => QualifiedAlias sch ix -> Definition db (Alter sch (DropSchemum ix 'Index schema) db)
+ Squeal.PostgreSQL.Definition.Index: dropIndexIfExists :: (Has sch db schema, KnownSymbol ix) => QualifiedAlias sch ix -> Definition db (Alter sch (DropSchemumIfExists ix 'Index schema) db)
+ Squeal.PostgreSQL.Definition.Index: gin :: IndexMethod 'Gin
+ Squeal.PostgreSQL.Definition.Index: gist :: IndexMethod 'Gist
+ Squeal.PostgreSQL.Definition.Index: hash :: IndexMethod 'Hash
+ Squeal.PostgreSQL.Definition.Index: instance forall k (ty :: k). GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Index.IndexMethod ty)
+ Squeal.PostgreSQL.Definition.Index: instance forall k (ty :: k). GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Index.IndexMethod ty)
+ Squeal.PostgreSQL.Definition.Index: instance forall k (ty :: k). GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Index.IndexMethod ty)
+ Squeal.PostgreSQL.Definition.Index: instance forall k (ty :: k). GHC.Show.Show (Squeal.PostgreSQL.Definition.Index.IndexMethod ty)
+ Squeal.PostgreSQL.Definition.Index: instance forall k (ty :: k). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Index.IndexMethod ty)
+ Squeal.PostgreSQL.Definition.Index: newtype IndexMethod ty
+ Squeal.PostgreSQL.Definition.Index: spgist :: IndexMethod 'Spgist
+ Squeal.PostgreSQL.Definition.Schema: createSchema :: KnownSymbol sch => Alias sch -> Definition db (Create sch '[] db)
+ Squeal.PostgreSQL.Definition.Schema: createSchemaIfNotExists :: (KnownSymbol sch, Has sch db schema) => Alias sch -> Definition db (CreateIfNotExists sch '[] db)
+ Squeal.PostgreSQL.Definition.Schema: dropSchemaCascade :: KnownSymbol sch => Alias sch -> Definition db (Drop sch db)
+ Squeal.PostgreSQL.Definition.Schema: dropSchemaCascadeIfExists :: KnownSymbol sch => Alias sch -> Definition db (DropIfExists sch db)
+ Squeal.PostgreSQL.Definition.Table: UnsafeAlterColumn :: ByteString -> AlterColumn
+ Squeal.PostgreSQL.Definition.Table: UnsafeAlterTable :: ByteString -> AlterTable
+ Squeal.PostgreSQL.Definition.Table: [renderAlterColumn] :: AlterColumn -> ByteString
+ Squeal.PostgreSQL.Definition.Table: [renderAlterTable] :: AlterTable -> ByteString
+ Squeal.PostgreSQL.Definition.Table: addColumn :: (AddColumn ty, KnownSymbol column, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias column -> ColumnTypeExpression db ty -> AlterTable sch tab db (constraints :=> Create column ty columns)
+ Squeal.PostgreSQL.Definition.Table: addConstraint :: (KnownSymbol alias, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias alias -> TableConstraintExpression sch tab db constraint -> AlterTable sch tab db (Create alias constraint constraints :=> columns)
+ Squeal.PostgreSQL.Definition.Table: alterColumn :: (KnownSymbol column, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns)), Has column columns ty0) => Alias column -> AlterColumn db ty0 ty1 -> AlterTable sch tab db (constraints :=> Alter column ty1 columns)
+ Squeal.PostgreSQL.Definition.Table: alterTable :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> AlterTable sch tab db table -> Definition db (Alter sch (Alter tab ( 'Table table) schema) db)
+ Squeal.PostgreSQL.Definition.Table: alterTableIfExists :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> AlterTable sch tab db table -> Definition db (Alter sch (AlterIfExists tab ( 'Table table) schema) db)
+ Squeal.PostgreSQL.Definition.Table: alterTableIfExistsRename :: (KnownSymbol tab0, KnownSymbol tab1) => Alias tab0 -> Alias tab1 -> Definition schema (RenameIfExists tab0 tab1 schema)
+ Squeal.PostgreSQL.Definition.Table: alterTableRename :: (KnownSymbol tab0, KnownSymbol tab1) => Alias tab0 -> Alias tab1 -> Definition schema (Rename tab0 tab1 schema)
+ Squeal.PostgreSQL.Definition.Table: alterType :: ColumnTypeExpression db ty -> AlterColumn db ty0 ty
+ Squeal.PostgreSQL.Definition.Table: class AddColumn ty
+ Squeal.PostgreSQL.Definition.Table: createTable :: (KnownSymbol sch, KnownSymbol tab, columns ~ (col : cols), SListI columns, SListI constraints, Has sch db0 schema0, db1 ~ Alter sch (Create tab ( 'Table (constraints :=> columns)) schema0) db0) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression db0)) columns -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints -> Definition db0 db1
+ Squeal.PostgreSQL.Definition.Table: createTableIfNotExists :: (KnownSymbol sch, KnownSymbol tab, columns ~ (col : cols), SListI columns, SListI constraints, Has sch db0 schema0, db1 ~ Alter sch (CreateIfNotExists tab ( 'Table (constraints :=> columns)) schema0) db0) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression db0)) columns -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints -> Definition db0 db1
+ Squeal.PostgreSQL.Definition.Table: dropColumn :: (KnownSymbol column, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias column -> AlterTable sch tab db (constraints :=> Drop column columns)
+ Squeal.PostgreSQL.Definition.Table: dropConstraint :: (KnownSymbol constraint, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias constraint -> AlterTable sch tab db (Drop constraint constraints :=> columns)
+ Squeal.PostgreSQL.Definition.Table: dropDefault :: AlterColumn db ( 'Def :=> ty) ( 'NoDef :=> ty)
+ Squeal.PostgreSQL.Definition.Table: dropNotNull :: AlterColumn db (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)
+ Squeal.PostgreSQL.Definition.Table: dropTable :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> Definition db (Alter sch (DropSchemum tab 'Table schema) db)
+ Squeal.PostgreSQL.Definition.Table: dropTableIfExists :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> Definition db (Alter sch (DropSchemumIfExists tab 'Table schema) db)
+ Squeal.PostgreSQL.Definition.Table: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
+ Squeal.PostgreSQL.Definition.Table: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
+ Squeal.PostgreSQL.Definition.Table: instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
+ Squeal.PostgreSQL.Definition.Table: instance Squeal.PostgreSQL.Definition.Table.AddColumn ('Squeal.PostgreSQL.Type.Schema.Def Squeal.PostgreSQL.Type.Schema.:=> ty)
+ Squeal.PostgreSQL.Definition.Table: instance Squeal.PostgreSQL.Definition.Table.AddColumn ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> 'Squeal.PostgreSQL.Type.Schema.Null ty)
+ Squeal.PostgreSQL.Definition.Table: newtype AlterColumn (db :: SchemasType) (ty0 :: ColumnType) (ty1 :: ColumnType)
+ Squeal.PostgreSQL.Definition.Table: newtype AlterTable (sch :: Symbol) (tab :: Symbol) (db :: SchemasType) (table :: TableType)
+ Squeal.PostgreSQL.Definition.Table: renameColumn :: (KnownSymbol column0, KnownSymbol column1, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias column0 -> Alias column1 -> AlterTable sch tab db (constraints :=> Rename column0 column1 columns)
+ Squeal.PostgreSQL.Definition.Table: setDefault :: Expression 'Ungrouped '[] '[] db '[] '[] ty -> AlterColumn db (constraint :=> ty) ( 'Def :=> ty)
+ Squeal.PostgreSQL.Definition.Table: setNotNull :: AlterColumn db (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)
+ Squeal.PostgreSQL.Definition.Type: createDomain :: (Has sch db schema, KnownSymbol dom) => QualifiedAlias sch dom -> (forall null. TypeExpression db (null ty)) -> (forall tab. Condition 'Ungrouped '[] '[] db '[] '[tab ::: '["value" ::: 'Null ty]]) -> Definition db (Alter sch (Create dom ( 'Typedef ty) schema) db)
+ Squeal.PostgreSQL.Definition.Type: createTypeComposite :: (KnownSymbol ty, Has sch db schema, SListI fields) => QualifiedAlias sch ty -> NP (Aliased (TypeExpression db)) fields -> Definition db (Alter sch (Create ty ( 'Typedef ( 'PGcomposite fields)) schema) db)
+ Squeal.PostgreSQL.Definition.Type: createTypeCompositeFrom :: forall hask sch ty db schema. (All (FieldTyped db) (RowPG hask), KnownSymbol ty, Has sch db schema) => QualifiedAlias sch ty -> Definition db (Alter sch (Create ty ( 'Typedef (PG (Composite hask))) schema) db)
+ Squeal.PostgreSQL.Definition.Type: createTypeEnum :: (KnownSymbol enum, Has sch db schema, All KnownSymbol labels) => QualifiedAlias sch enum -> NP PGlabel labels -> Definition db (Alter sch (Create enum ( 'Typedef ( 'PGenum labels)) schema) db)
+ Squeal.PostgreSQL.Definition.Type: createTypeEnumFrom :: forall hask sch enum db schema. (Generic hask, All KnownSymbol (LabelsPG hask), KnownSymbol enum, Has sch db schema) => QualifiedAlias sch enum -> Definition db (Alter sch (Create enum ( 'Typedef (PG (Enumerated hask))) schema) db)
+ Squeal.PostgreSQL.Definition.Type: createTypeRange :: (Has sch db schema, KnownSymbol range) => QualifiedAlias sch range -> (forall null. TypeExpression db (null ty)) -> Definition db (Alter sch (Create range ( 'Typedef ( 'PGrange ty)) schema) db)
+ Squeal.PostgreSQL.Definition.Type: dropType :: (Has sch db schema, KnownSymbol td) => QualifiedAlias sch td -> Definition db (Alter sch (DropSchemum td 'Typedef schema) db)
+ Squeal.PostgreSQL.Definition.Type: dropTypeIfExists :: (Has sch db schema, KnownSymbol td) => QualifiedAlias sch td -> Definition db (Alter sch (DropSchemumIfExists td 'Typedef schema) db)
+ Squeal.PostgreSQL.Definition.View: createOrReplaceView :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Query '[] '[] db '[] view -> Definition db (Alter sch (CreateOrReplace vw ( 'View view) schema) db)
+ Squeal.PostgreSQL.Definition.View: createView :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Query '[] '[] db '[] view -> Definition db (Alter sch (Create vw ( 'View view) schema) db)
+ Squeal.PostgreSQL.Definition.View: dropView :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Definition db (Alter sch (DropSchemum vw 'View schema) db)
+ Squeal.PostgreSQL.Definition.View: dropViewIfExists :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Definition db (Alter sch (DropIfExists vw schema) db)
+ Squeal.PostgreSQL.Expression: (@&&) :: PGIntersect ty => Operator (null0 ty) (null1 ty) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression: class PGIntersect ty
+ Squeal.PostgreSQL.Expression: function :: (Has sch db schema, Has fun schema ( 'Function ('[x] :=> 'Returns y))) => QualifiedAlias sch fun -> Fun db x y
+ Squeal.PostgreSQL.Expression: functionN :: (Has sch db schema, Has fun schema ( 'Function (xs :=> 'Returns y)), SListI xs) => QualifiedAlias sch fun -> FunN db xs y
+ Squeal.PostgreSQL.Expression: instance (GHC.TypeLits.KnownSymbol label, Squeal.PostgreSQL.Type.List.In label labels) => Squeal.PostgreSQL.Type.Schema.IsPGlabel label (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null ('Squeal.PostgreSQL.Type.Schema.PGenum labels)))
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) column)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from)) columns)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, tys Data.Type.Equality.~ '[ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) tys)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) column)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from)) columns)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, tys Data.Type.Equality.~ '[ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) tys)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) column)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from)) columns)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, tys Data.Type.Equality.~ '[ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) tys)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) column)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from)) columns)
+ Squeal.PostgreSQL.Expression: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, tys Data.Type.Equality.~ '[ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) tys)
+ Squeal.PostgreSQL.Expression: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtext))
+ Squeal.PostgreSQL.Expression: instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsquery))
+ Squeal.PostgreSQL.Expression: instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsvector))
+ Squeal.PostgreSQL.Expression: instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtext))
+ Squeal.PostgreSQL.Expression: instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsvector))
+ Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGjsonb))
+ Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtext))
+ Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsvector))
+ Squeal.PostgreSQL.Expression: instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null ('Squeal.PostgreSQL.Type.Schema.PGvararray ty)))
+ Squeal.PostgreSQL.Expression: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat4))
+ Squeal.PostgreSQL.Expression: instance GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat8))
+ Squeal.PostgreSQL.Expression: instance GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGnumeric))
+ Squeal.PostgreSQL.Expression: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat4))
+ Squeal.PostgreSQL.Expression: instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat8))
+ Squeal.PostgreSQL.Expression: instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGint2))
+ Squeal.PostgreSQL.Expression: instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGint4))
+ Squeal.PostgreSQL.Expression: instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGint8))
+ Squeal.PostgreSQL.Expression: instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGnumeric))
+ Squeal.PostgreSQL.Expression: instance GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat4))
+ Squeal.PostgreSQL.Expression: instance GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat8))
+ Squeal.PostgreSQL.Expression: instance GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGnumeric))
+ Squeal.PostgreSQL.Expression: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGIntersect ('Squeal.PostgreSQL.Type.Schema.PGrange ty)
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGIntersect ('Squeal.PostgreSQL.Type.Schema.PGvararray ty)
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Type.Schema.PGjsonb
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Type.Schema.PGtsquery
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset ('Squeal.PostgreSQL.Type.Schema.PGrange ty)
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Expression.PGSubset ('Squeal.PostgreSQL.Type.Schema.PGvararray ty)
+ Squeal.PostgreSQL.Expression: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression: type Fun db x y = forall grp lat with params from. Expression grp lat with db params from x " input" -> Expression grp lat with db params from y " output"
+ Squeal.PostgreSQL.Expression: type FunN db xs y = forall grp lat with params from. NP (Expression grp lat with db params from) xs " inputs" -> Expression grp lat with db params from y " output"
+ Squeal.PostgreSQL.Expression: type OperatorDB db x1 x2 y = forall grp lat with params from. Expression grp lat with db params from x1 " left input" -> Expression grp lat with db params from x2 " right input" -> Expression grp lat with db params from y " output"
+ Squeal.PostgreSQL.Expression: unsafeLeftOp :: ByteString -> x --> y
+ Squeal.PostgreSQL.Expression: unsafeRightOp :: ByteString -> x --> y
+ Squeal.PostgreSQL.Expression.Aggregate: AggregateAll :: NP (Expression 'Ungrouped lat with db params from) xs -> [SortExpression 'Ungrouped lat with db params from] -> [Condition 'Ungrouped lat with db params from] -> AggregateArg
+ Squeal.PostgreSQL.Expression.Aggregate: AggregateDistinct :: NP (Expression 'Ungrouped lat with db params from) xs -> [SortExpression 'Ungrouped lat with db params from] -> [Condition 'Ungrouped lat with db params from] -> AggregateArg
+ Squeal.PostgreSQL.Expression.Aggregate: [aggregateArgs] :: AggregateArg -> NP (Expression 'Ungrouped lat with db params from) xs
+ Squeal.PostgreSQL.Expression.Aggregate: [aggregateFilter] :: AggregateArg -> [Condition 'Ungrouped lat with db params from]
+ Squeal.PostgreSQL.Expression.Aggregate: [aggregateOrder] :: AggregateArg -> [SortExpression 'Ungrouped lat with db params from]
+ Squeal.PostgreSQL.Expression.Aggregate: allNotNull :: Expression 'Ungrouped lat with db params from ( 'Null x) -> AggregateArg '[ 'NotNull x] lat with db params from
+ Squeal.PostgreSQL.Expression.Aggregate: class FilterWhere arg grp | arg -> grp
+ Squeal.PostgreSQL.Expression.Aggregate: data AggregateArg (xs :: [NullType]) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
+ Squeal.PostgreSQL.Expression.Aggregate: distinctNotNull :: Expression 'Ungrouped lat with db params from ( 'Null x) -> AggregateArg '[ 'NotNull x] lat with db params from
+ Squeal.PostgreSQL.Expression.Aggregate: filterWhere :: FilterWhere arg grp => Condition grp lat with db params from -> arg xs lat with db params from -> arg xs lat with db params from
+ Squeal.PostgreSQL.Expression.Aggregate: instance Data.SOP.Constraint.SListI xs => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Aggregate.AggregateArg xs lat with db params from)
+ Squeal.PostgreSQL.Expression.Aggregate: instance Squeal.PostgreSQL.Expression.Aggregate.Aggregate Squeal.PostgreSQL.Expression.Aggregate.AggregateArg (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys))
+ Squeal.PostgreSQL.Expression.Aggregate: instance Squeal.PostgreSQL.Expression.Aggregate.FilterWhere Squeal.PostgreSQL.Expression.Aggregate.AggregateArg 'Squeal.PostgreSQL.Type.Alias.Ungrouped
+ Squeal.PostgreSQL.Expression.Aggregate: instance Squeal.PostgreSQL.Expression.Sort.OrderBy (Squeal.PostgreSQL.Expression.Aggregate.AggregateArg xs) 'Squeal.PostgreSQL.Type.Alias.Ungrouped
+ Squeal.PostgreSQL.Expression.Aggregate: pattern All :: Expression 'Ungrouped lat with db params from x -> AggregateArg '[x] lat with db params from
+ Squeal.PostgreSQL.Expression.Aggregate: pattern Alls :: NP (Expression 'Ungrouped lat with db params from) xs -> AggregateArg xs lat with db params from
+ Squeal.PostgreSQL.Expression.Aggregate: pattern Distinct :: Expression 'Ungrouped lat with db params from x -> AggregateArg '[x] lat with db params from
+ Squeal.PostgreSQL.Expression.Aggregate: pattern Distincts :: NP (Expression 'Ungrouped lat with db params from) xs -> AggregateArg xs lat with db params from
+ Squeal.PostgreSQL.Expression.Array: array :: [Expression grp lat with db params from ty] -> Expression grp lat with db params from (null ( 'PGvararray ty))
+ Squeal.PostgreSQL.Expression.Array: array0 :: TypeExpression db ty -> Expression grp lat with db params from (null ( 'PGvararray ty))
+ Squeal.PostgreSQL.Expression.Array: array1 :: (n ~ Length tys, All ((~) ty) tys) => NP (Expression grp lat with db params from) tys -> Expression grp lat with db params from (null ( 'PGfixarray '[n] ty))
+ Squeal.PostgreSQL.Expression.Array: array2 :: (All ((~) tys) tyss, All SListI tyss, Length tyss ~ n1, All ((~) ty) tys, Length tys ~ n2) => NP (NP (Expression grp lat with db params from)) tyss -> Expression grp lat with db params from (null ( 'PGfixarray '[n1, n2] ty))
+ Squeal.PostgreSQL.Expression.Array: cardinality :: null ( 'PGvararray ty) --> null 'PGint8
+ Squeal.PostgreSQL.Expression.Array: index :: Word64 -> null ( 'PGvararray ty) --> NullifyType ty
+ Squeal.PostgreSQL.Expression.Array: unnest :: null ( 'PGvararray ty) -|-> ("unnest" ::: '["unnest" ::: ty])
+ Squeal.PostgreSQL.Expression.Composite: field :: (Has sch db schema, Has tydef schema ( 'Typedef ( 'PGcomposite row)), Has field row ty) => QualifiedAlias sch tydef -> Alias field -> Expression grp lat with db params from ( 'NotNull ( 'PGcomposite row)) -> Expression grp lat with db params from ty
+ Squeal.PostgreSQL.Expression.Composite: row :: SListI row => NP (Aliased (Expression grp lat with db params from)) row -> Expression grp lat with db params from (null ( 'PGcomposite row))
+ Squeal.PostgreSQL.Expression.Composite: rowStar :: Has tab from row => Alias tab -> Expression grp lat with db params from (null ( 'PGcomposite row))
+ Squeal.PostgreSQL.Expression.Default: [Default] :: Optional expr ( 'Def :=> ty)
+ Squeal.PostgreSQL.Expression.Default: [Set] :: expr ty -> Optional expr (def :=> ty)
+ Squeal.PostgreSQL.Expression.Default: data Optional (expr :: k -> Type) (ty :: (Optionality, k))
+ Squeal.PostgreSQL.Expression.Default: instance forall k (expr :: k -> *) (ty :: (Squeal.PostgreSQL.Type.Schema.Optionality, k)). (forall (x :: k). Squeal.PostgreSQL.Render.RenderSQL (expr x)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Default.Optional expr ty)
+ Squeal.PostgreSQL.Expression.Default: mapOptional :: (expr x -> expr y) -> Optional expr (def :=> x) -> Optional expr (def :=> y)
+ Squeal.PostgreSQL.Expression.Default: pattern NotDefault :: ty -> Optional I ( 'Def :=> ty)
+ Squeal.PostgreSQL.Expression.Inline: class Inline x
+ Squeal.PostgreSQL.Expression.Inline: class InlineColumn (field :: (Symbol, Type)) (column :: (Symbol, ColumnType))
+ Squeal.PostgreSQL.Expression.Inline: class InlineField (field :: (Symbol, Type)) (fieldpg :: (Symbol, NullType))
+ Squeal.PostgreSQL.Expression.Inline: class InlineParam x ty
+ Squeal.PostgreSQL.Expression.Inline: inline :: Inline x => x -> Expr (null (PG x))
+ Squeal.PostgreSQL.Expression.Inline: inlineColumn :: InlineColumn field column => P field -> Aliased (Optional (Expression grp lat with db params from)) column
+ Squeal.PostgreSQL.Expression.Inline: inlineColumns :: (IsRecord hask xs, AllZip InlineColumn xs columns) => hask -> NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns
+ Squeal.PostgreSQL.Expression.Inline: inlineField :: InlineField field fieldpg => P field -> Aliased (Expression grp lat with db params from) fieldpg
+ Squeal.PostgreSQL.Expression.Inline: inlineFields :: (IsRecord hask fields, AllZip InlineField fields row) => hask -> NP (Aliased (Expression 'Ungrouped '[] with db params '[])) row
+ Squeal.PostgreSQL.Expression.Inline: inlineParam :: InlineParam x ty => x -> Expr ty
+ Squeal.PostgreSQL.Expression.Inline: instance (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Expression.Inline.InlineParam x ty) => Squeal.PostgreSQL.Expression.Inline.InlineField (alias Squeal.PostgreSQL.Type.Alias.::: x) (alias Squeal.PostgreSQL.Type.Alias.::: ty)
+ Squeal.PostgreSQL.Expression.Inline: instance (GHC.TypeLits.KnownSymbol col, Squeal.PostgreSQL.Expression.Inline.InlineParam x ty) => Squeal.PostgreSQL.Expression.Inline.InlineColumn (col Squeal.PostgreSQL.Type.Alias.::: Squeal.PostgreSQL.Expression.Default.Optional Data.SOP.BasicFunctors.I ('Squeal.PostgreSQL.Type.Schema.Def Squeal.PostgreSQL.Type.Schema.:=> x)) (col Squeal.PostgreSQL.Type.Alias.::: ('Squeal.PostgreSQL.Type.Schema.Def Squeal.PostgreSQL.Type.Schema.:=> ty))
+ Squeal.PostgreSQL.Expression.Inline: instance (GHC.TypeLits.KnownSymbol col, Squeal.PostgreSQL.Expression.Inline.InlineParam x ty) => Squeal.PostgreSQL.Expression.Inline.InlineColumn (col Squeal.PostgreSQL.Type.Alias.::: x) (col Squeal.PostgreSQL.Type.Alias.::: ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> ty))
+ Squeal.PostgreSQL.Expression.Inline: instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.FixChar n)
+ Squeal.PostgreSQL.Expression.Inline: instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.VarChar n)
+ Squeal.PostgreSQL.Expression.Inline: instance (Generics.SOP.Record.IsRecord x xs, Data.SOP.Constraint.AllZip Squeal.PostgreSQL.Expression.Inline.InlineField xs (Squeal.PostgreSQL.Type.PG.RowPG x)) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Composite x)
+ Squeal.PostgreSQL.Expression.Inline: instance (Generics.SOP.Universe.IsEnumType x, Generics.SOP.Universe.HasDatatypeInfo x) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Enumerated x)
+ Squeal.PostgreSQL.Expression.Inline: instance (Squeal.PostgreSQL.Expression.Inline.Inline x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Expression.Inline.InlineParam (GHC.Maybe.Maybe x) ('Squeal.PostgreSQL.Type.Schema.Null pg)
+ Squeal.PostgreSQL.Expression.Inline: instance (Squeal.PostgreSQL.Expression.Inline.Inline x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Expression.Inline.InlineParam x ('Squeal.PostgreSQL.Type.Schema.NotNull pg)
+ Squeal.PostgreSQL.Expression.Inline: instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Json x)
+ Squeal.PostgreSQL.Expression.Inline: instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Jsonb x)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Scientific.Scientific)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Time.Calendar.Days.Day)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Time.Clock.Internal.UTCTime.UTCTime)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Time.LocalTime.Internal.LocalTime.LocalTime)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range GHC.Int.Int32)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range GHC.Int.Int64)
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Scientific.Scientific
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Text.Internal.Lazy.Text
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Text.Internal.Text
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.Calendar.Days.Day
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.Clock.Internal.DiffTime.DiffTime
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.Clock.Internal.UTCTime.UTCTime
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Data.UUID.Types.Internal.UUID
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Database.PostgreSQL.LibPQ.Oid
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Base.String
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Int.Int16
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Int.Int32
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Int.Int64
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Bool
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Char
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Double
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Float
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.Inline Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.InlineParam x (Squeal.PostgreSQL.Type.PG.NullPG x) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector x))
+ Squeal.PostgreSQL.Expression.Inline: instance Squeal.PostgreSQL.Expression.Inline.InlineParam x (Squeal.PostgreSQL.Type.PG.NullPG x) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.VarArray [x])
+ Squeal.PostgreSQL.Expression.Json: instance (Squeal.PostgreSQL.Expression.Json.JsonBuildObject tys, Squeal.PostgreSQL.Type.List.In key Squeal.PostgreSQL.Type.Schema.PGJsonKey) => Squeal.PostgreSQL.Expression.Json.JsonBuildObject ('Squeal.PostgreSQL.Type.Schema.NotNull key : value : tys)
+ Squeal.PostgreSQL.Expression.Null: monoNotNull :: (forall null. Expression grp lat with db params from (null ty)) -> Expression grp lat with db params from ( 'NotNull ty)
+ Squeal.PostgreSQL.Expression.Null: unsafeNotNull :: 'Null ty --> 'NotNull ty
+ Squeal.PostgreSQL.Expression.Range: (&<) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: (&>) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: (-|-) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: (.<@) :: Operator ( 'NotNull ty) (null ( 'PGrange ty)) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: (<..<) :: x -> x -> Range x
+ Squeal.PostgreSQL.Expression.Range: (<..<=) :: x -> x -> Range x
+ Squeal.PostgreSQL.Expression.Range: (<<@) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: (<=..<) :: x -> x -> Range x
+ Squeal.PostgreSQL.Expression.Range: (<=..<=) :: x -> x -> Range x
+ Squeal.PostgreSQL.Expression.Range: (@*) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) (null ( 'PGrange ty))
+ Squeal.PostgreSQL.Expression.Range: (@+) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) (null ( 'PGrange ty))
+ Squeal.PostgreSQL.Expression.Range: (@-) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) (null ( 'PGrange ty))
+ Squeal.PostgreSQL.Expression.Range: (@>.) :: Operator (null ( 'PGrange ty)) ( 'NotNull ty) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: (@>>) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Range: Closed :: x -> Bound x
+ Squeal.PostgreSQL.Expression.Range: Empty :: Range x
+ Squeal.PostgreSQL.Expression.Range: Infinite :: Bound x
+ Squeal.PostgreSQL.Expression.Range: NonEmpty :: Bound x -> Bound x -> Range x
+ Squeal.PostgreSQL.Expression.Range: Open :: x -> Bound x
+ Squeal.PostgreSQL.Expression.Range: atLeast :: x -> Range x
+ Squeal.PostgreSQL.Expression.Range: atMost :: x -> Range x
+ Squeal.PostgreSQL.Expression.Range: data Bound x
+ Squeal.PostgreSQL.Expression.Range: data Range x
+ Squeal.PostgreSQL.Expression.Range: infix 4 <..<=
+ Squeal.PostgreSQL.Expression.Range: instance Data.Foldable.Foldable Squeal.PostgreSQL.Expression.Range.Bound
+ Squeal.PostgreSQL.Expression.Range: instance Data.Foldable.Foldable Squeal.PostgreSQL.Expression.Range.Range
+ Squeal.PostgreSQL.Expression.Range: instance Data.Traversable.Traversable Squeal.PostgreSQL.Expression.Range.Bound
+ Squeal.PostgreSQL.Expression.Range: instance Data.Traversable.Traversable Squeal.PostgreSQL.Expression.Range.Range
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Base.Functor Squeal.PostgreSQL.Expression.Range.Bound
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Base.Functor Squeal.PostgreSQL.Expression.Range.Range
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Range.Bound x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Range.Bound x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Range.Bound x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Expression.Range.Bound x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Expression.Range.Bound x)
+ Squeal.PostgreSQL.Expression.Range: instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Expression.Range: instance Squeal.PostgreSQL.Type.PG.IsPG hask => Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Expression.Range.Range hask)
+ Squeal.PostgreSQL.Expression.Range: isEmpty :: null ( 'PGrange ty) --> 'Null 'PGbool
+ Squeal.PostgreSQL.Expression.Range: lessThan :: x -> Range x
+ Squeal.PostgreSQL.Expression.Range: lowerBound :: null ( 'PGrange ty) --> 'Null ty
+ Squeal.PostgreSQL.Expression.Range: lowerInc :: null ( 'PGrange ty) --> 'Null 'PGbool
+ Squeal.PostgreSQL.Expression.Range: lowerInf :: null ( 'PGrange ty) --> 'Null 'PGbool
+ Squeal.PostgreSQL.Expression.Range: moreThan :: x -> Range x
+ Squeal.PostgreSQL.Expression.Range: range :: TypeExpression db (null ( 'PGrange ty)) -> Range (Expression grp lat with db params from ( 'NotNull ty)) -> Expression grp lat with db params from (null ( 'PGrange ty))
+ Squeal.PostgreSQL.Expression.Range: rangeMerge :: '[null ( 'PGrange ty), null ( 'PGrange ty)] ---> null ( 'PGrange ty)
+ Squeal.PostgreSQL.Expression.Range: singleton :: x -> Range x
+ Squeal.PostgreSQL.Expression.Range: upperBound :: null ( 'PGrange ty) --> 'Null ty
+ Squeal.PostgreSQL.Expression.Range: upperInc :: null ( 'PGrange ty) --> 'Null 'PGbool
+ Squeal.PostgreSQL.Expression.Range: upperInf :: null ( 'PGrange ty) --> 'Null 'PGbool
+ Squeal.PostgreSQL.Expression.Range: whole :: Range x
+ Squeal.PostgreSQL.Expression.Sort: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Sort.SortExpression grp lat with db params from)
+ Squeal.PostgreSQL.Expression.Sort: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Sort.SortExpression grp lat with db params from)
+ Squeal.PostgreSQL.Expression.Sort: instance Squeal.PostgreSQL.Render.RenderSQL [Squeal.PostgreSQL.Expression.Sort.SortExpression grp lat with db params from]
+ Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGdate 'Squeal.PostgreSQL.Type.Schema.PGint4
+ Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGinterval 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtime 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtimestamp 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Expression.Time: instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtimetz 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Expression.Type: UnsafeColumnTypeExpression :: ByteString -> ColumnTypeExpression
+ Squeal.PostgreSQL.Expression.Type: [renderColumnTypeExpression] :: ColumnTypeExpression -> ByteString
+ Squeal.PostgreSQL.Expression.Type: bigserial :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint8)
+ Squeal.PostgreSQL.Expression.Type: class ColumnTyped db (column :: ColumnType)
+ Squeal.PostgreSQL.Expression.Type: class FieldTyped db ty
+ Squeal.PostgreSQL.Expression.Type: class NullTyped db (ty :: NullType)
+ Squeal.PostgreSQL.Expression.Type: columntype :: ColumnTyped db column => ColumnTypeExpression db column
+ Squeal.PostgreSQL.Expression.Type: columntypeFrom :: forall hask db. ColumnTyped db ( 'NoDef :=> NullPG hask) => ColumnTypeExpression db ( 'NoDef :=> NullPG hask)
+ Squeal.PostgreSQL.Expression.Type: daterange :: TypeExpression db (null ( 'PGrange 'PGdate))
+ Squeal.PostgreSQL.Expression.Type: default_ :: Expression 'Ungrouped '[] '[] db '[] '[] ty -> ColumnTypeExpression db ( 'NoDef :=> ty) -> ColumnTypeExpression db ( 'Def :=> ty)
+ Squeal.PostgreSQL.Expression.Type: fieldtype :: FieldTyped db ty => Aliased (TypeExpression db) ty
+ Squeal.PostgreSQL.Expression.Type: instance (Data.SOP.Constraint.All GHC.TypeNats.KnownNat dims, Squeal.PostgreSQL.Expression.Type.PGTyped db pg) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGfixarray dims (null pg))
+ Squeal.PostgreSQL.Expression.Type: instance (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Expression.Type.NullTyped db ty) => Squeal.PostgreSQL.Expression.Type.FieldTyped db (alias Squeal.PostgreSQL.Type.Alias.::: ty)
+ Squeal.PostgreSQL.Expression.Type: instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGchar n)
+ Squeal.PostgreSQL.Expression.Type: instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGvarchar n)
+ Squeal.PostgreSQL.Expression.Type: instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGcomposite row))) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row)
+ Squeal.PostgreSQL.Expression.Type: instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGenum labels)
+ Squeal.PostgreSQL.Expression.Type: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.NullTyped db ('Squeal.PostgreSQL.Type.Schema.NotNull ty) => Squeal.PostgreSQL.Expression.Type.ColumnTyped db ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> 'Squeal.PostgreSQL.Type.Schema.NotNull ty)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.NullTyped db ('Squeal.PostgreSQL.Type.Schema.Null ty) => Squeal.PostgreSQL.Expression.Type.ColumnTyped db ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> 'Squeal.PostgreSQL.Type.Schema.Null ty)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGbool
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGbytea
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGdate
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGfloat4
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGfloat8
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGint2
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGint4
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGint8
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGjson
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGjsonb
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGmoney
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGnumeric
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGoid
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtext
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtime
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtimestamp
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtimetz
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtsquery
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtsvector
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGuuid
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGdate)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint4)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint8)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGnumeric)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamp)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db pg => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGvararray (null pg))
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Expression.Type.PGTyped db ty => Squeal.PostgreSQL.Expression.Type.NullTyped db (null ty)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty)
+ Squeal.PostgreSQL.Expression.Type: int4range :: TypeExpression db (null ( 'PGrange 'PGint4))
+ Squeal.PostgreSQL.Expression.Type: int8range :: TypeExpression db (null ( 'PGrange 'PGint8))
+ Squeal.PostgreSQL.Expression.Type: newtype ColumnTypeExpression (db :: SchemasType) (ty :: ColumnType)
+ Squeal.PostgreSQL.Expression.Type: notNullable :: TypeExpression db (null ty) -> ColumnTypeExpression db ( 'NoDef :=> 'NotNull ty)
+ Squeal.PostgreSQL.Expression.Type: nullable :: TypeExpression db (null ty) -> ColumnTypeExpression db ( 'NoDef :=> 'Null ty)
+ Squeal.PostgreSQL.Expression.Type: nulltype :: NullTyped db ty => TypeExpression db ty
+ Squeal.PostgreSQL.Expression.Type: nulltypeFrom :: forall hask db. NullTyped db (NullPG hask) => TypeExpression db (NullPG hask)
+ Squeal.PostgreSQL.Expression.Type: numrange :: TypeExpression db (null ( 'PGrange 'PGnumeric))
+ Squeal.PostgreSQL.Expression.Type: oid :: TypeExpression db (null 'PGoid)
+ Squeal.PostgreSQL.Expression.Type: pgtypeFrom :: forall hask db null. PGTyped db (PG hask) => TypeExpression db (null (PG hask))
+ Squeal.PostgreSQL.Expression.Type: record :: TypeExpression db (null ( 'PGcomposite record))
+ Squeal.PostgreSQL.Expression.Type: serial :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint4)
+ Squeal.PostgreSQL.Expression.Type: serial2 :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint2)
+ Squeal.PostgreSQL.Expression.Type: serial4 :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint4)
+ Squeal.PostgreSQL.Expression.Type: serial8 :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint8)
+ Squeal.PostgreSQL.Expression.Type: smallserial :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint2)
+ Squeal.PostgreSQL.Expression.Type: timestamptz :: TypeExpression db (null 'PGtimestamptz)
+ Squeal.PostgreSQL.Expression.Type: timetz :: TypeExpression db (null 'PGtimetz)
+ Squeal.PostgreSQL.Expression.Type: tsrange :: TypeExpression db (null ( 'PGrange 'PGtimestamp))
+ Squeal.PostgreSQL.Expression.Type: tstzrange :: TypeExpression db (null ( 'PGrange 'PGtimestamptz))
+ Squeal.PostgreSQL.Expression.Window: WindowArg :: NP (Expression grp lat with db params from) args -> [Condition grp lat with db params from] -> WindowArg
+ Squeal.PostgreSQL.Expression.Window: [windowArgs] :: WindowArg -> NP (Expression grp lat with db params from) args
+ Squeal.PostgreSQL.Expression.Window: [windowFilter] :: WindowArg -> [Condition grp lat with db params from]
+ Squeal.PostgreSQL.Expression.Window: data WindowArg (grp :: Grouping) (args :: [NullType]) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
+ Squeal.PostgreSQL.Expression.Window: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression.Window: instance Data.SOP.Constraint.SListI args => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowArg grp args lat with db params from)
+ Squeal.PostgreSQL.Expression.Window: instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression.Window: instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression.Window: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Window.WindowArg grp args lat with db params from)
+ Squeal.PostgreSQL.Expression.Window: instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression.Window: instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Expression.Aggregate.Aggregate (Squeal.PostgreSQL.Expression.Window.WindowArg grp) (Squeal.PostgreSQL.Expression.Window.WindowFunction grp)
+ Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Expression.Aggregate.FilterWhere (Squeal.PostgreSQL.Expression.Window.WindowArg grp) grp
+ Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Expression.Sort.OrderBy (Squeal.PostgreSQL.Expression.Window.WindowDefinition grp) grp
+ Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowDefinition lat with db from grp params)
+ Squeal.PostgreSQL.Expression.Window: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty)
+ Squeal.PostgreSQL.Expression.Window: pattern Window :: Expression grp lat with db params from arg -> WindowArg grp '[arg] lat with db params from
+ Squeal.PostgreSQL.Expression.Window: pattern Windows :: NP (Expression grp lat with db params from) args -> WindowArg grp args lat with db params from
+ Squeal.PostgreSQL.Expression.Window: type (--#->) xs y = forall grp lat with db params from. WindowArg grp xs lat with db params from " inputs" -> WindowFunction grp lat with db params from y " output"
+ Squeal.PostgreSQL.Manipulation: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Manipulation.Manipulation with db params columns)
+ Squeal.PostgreSQL.Manipulation: instance GHC.Classes.Eq (Squeal.PostgreSQL.Manipulation.Manipulation with db params columns)
+ Squeal.PostgreSQL.Manipulation: instance GHC.Classes.Ord (Squeal.PostgreSQL.Manipulation.Manipulation with db params columns)
+ Squeal.PostgreSQL.Manipulation: instance GHC.Generics.Generic (Squeal.PostgreSQL.Manipulation.Manipulation with db params columns)
+ Squeal.PostgreSQL.Manipulation: instance GHC.Show.Show (Squeal.PostgreSQL.Manipulation.Manipulation with db params columns)
+ Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Query.With.With Squeal.PostgreSQL.Manipulation.Manipulation
+ Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Manipulation with db params columns)
+ Squeal.PostgreSQL.Manipulation: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.ReturningClause with db params from row)
+ Squeal.PostgreSQL.Manipulation.Delete: [NoUsing] :: UsingClause with db params '[]
+ Squeal.PostgreSQL.Manipulation.Delete: [Using] :: FromClause '[] with db params from -> UsingClause with db params from
+ Squeal.PostgreSQL.Manipulation.Delete: data UsingClause with db params from
+ Squeal.PostgreSQL.Manipulation.Delete: deleteFrom :: (SListI row, Has sch db schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> UsingClause with db params from -> Condition 'Ungrouped '[] with db params ((tab ::: TableToRow table) : from) -> ReturningClause with db params '[tab ::: TableToRow table] row -> Manipulation with db params row
+ Squeal.PostgreSQL.Manipulation.Delete: deleteFrom_ :: (Has sch db schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> Condition 'Ungrouped '[] with db params '[tab ::: TableToRow table] -> Manipulation with db params '[]
+ Squeal.PostgreSQL.Manipulation.Insert: [DoNothing] :: ConflictAction tab with db params table
+ Squeal.PostgreSQL.Manipulation.Insert: [DoUpdate] :: (row ~ TableToRow table, from ~ '[tab ::: row, "excluded" ::: row], Updatable table updates) => NP (Aliased (Optional (Expression 'Ungrouped '[] with db params from))) updates -> [Condition 'Ungrouped '[] with db params from] -> ConflictAction tab with db params table
+ Squeal.PostgreSQL.Manipulation.Insert: [OnConflictDoRaise] :: ConflictClause tab with db params table
+ Squeal.PostgreSQL.Manipulation.Insert: [OnConflict] :: ConflictTarget table -> ConflictAction tab with db params table -> ConflictClause tab with db params table
+ Squeal.PostgreSQL.Manipulation.Insert: [OnConstraint] :: Has con constraints constraint => Alias con -> ConflictTarget (constraints :=> columns)
+ Squeal.PostgreSQL.Manipulation.Insert: [Select] :: SListI columns => NP (Aliased (Optional (Expression grp '[] with db params from))) columns -> TableExpression grp '[] with db params from -> QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Insert: [Subquery] :: ColumnsToRow columns ~ row => Query '[] with db params row -> QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Insert: [Values] :: SListI columns => NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns -> [NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns] -> QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Insert: data ConflictAction tab with db params table
+ Squeal.PostgreSQL.Manipulation.Insert: data ConflictClause tab with db params table
+ Squeal.PostgreSQL.Manipulation.Insert: data ConflictTarget table
+ Squeal.PostgreSQL.Manipulation.Insert: data QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Insert: inlineValues :: (IsRecord hask xs, AllZip InlineColumn xs columns) => hask -> [hask] -> QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Insert: inlineValues_ :: (IsRecord hask xs, AllZip InlineColumn xs columns) => hask -> QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Insert: insertInto :: (Has sch db schema, Has tab schema ( 'Table table), SListI (TableToColumns table), SListI row) => QualifiedAlias sch tab -> QueryClause with db params (TableToColumns table) -> ConflictClause tab with db params table -> ReturningClause with db params '[tab ::: TableToRow table] row -> Manipulation with db params row
+ Squeal.PostgreSQL.Manipulation.Insert: insertInto_ :: (Has sch db schema, Has tab schema ( 'Table table), SListI (TableToColumns table)) => QualifiedAlias sch tab -> QueryClause with db params (TableToColumns table) -> Manipulation with db params '[]
+ Squeal.PostgreSQL.Manipulation.Insert: instance Data.SOP.Constraint.SListI (Squeal.PostgreSQL.Type.Schema.TableToColumns table) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Insert.ConflictClause tab with db params table)
+ Squeal.PostgreSQL.Manipulation.Insert: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Insert.ConflictAction tab with db params table)
+ Squeal.PostgreSQL.Manipulation.Insert: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Insert.QueryClause with db params columns)
+ Squeal.PostgreSQL.Manipulation.Insert: instance forall kind k (constraints :: ([(GHC.Types.Symbol, kind)], k)). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Manipulation.Insert.ConflictTarget constraints)
+ Squeal.PostgreSQL.Manipulation.Insert: pattern Values_ :: SListI columns => NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns -> QueryClause with db params columns
+ Squeal.PostgreSQL.Manipulation.Update: update :: (Has sch db schema, Has tab schema ( 'Table table), Updatable table updates, SListI row) => QualifiedAlias sch tab -> NP (Aliased (Optional (Expression 'Ungrouped '[] '[] db params '[tab ::: TableToRow table]))) updates -> Condition 'Ungrouped '[] with db params '[tab ::: TableToRow table] -> ReturningClause with db params '[tab ::: TableToRow table] row -> Manipulation with db params row
+ Squeal.PostgreSQL.Manipulation.Update: update_ :: (Has sch db schema, Has tab schema ( 'Table table), Updatable table updates) => QualifiedAlias sch tab -> NP (Aliased (Optional (Expression 'Ungrouped '[] '[] db params '[tab ::: TableToRow table]))) updates -> Condition 'Ungrouped '[] with db params '[tab ::: TableToRow table] -> Manipulation with db params '[]
+ Squeal.PostgreSQL.Query: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.Query lat with db params row)
+ Squeal.PostgreSQL.Query: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Query lat with db params row)
+ Squeal.PostgreSQL.Query: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Query lat with db params row)
+ Squeal.PostgreSQL.Query: instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.Query lat with db params row)
+ Squeal.PostgreSQL.Query: instance GHC.Show.Show (Squeal.PostgreSQL.Query.Query lat with db params row)
+ Squeal.PostgreSQL.Query: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Query lat with db params row)
+ Squeal.PostgreSQL.Query.From: UnsafeFromClause :: ByteString -> FromClause
+ Squeal.PostgreSQL.Query.From: [renderFromClause] :: FromClause -> ByteString
+ Squeal.PostgreSQL.Query.From: common :: Has cte with common => Aliased Alias (alias ::: cte) -> FromClause lat with db params '[alias ::: common]
+ Squeal.PostgreSQL.Query.From: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
+ Squeal.PostgreSQL.Query.From: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
+ Squeal.PostgreSQL.Query.From: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
+ Squeal.PostgreSQL.Query.From: instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
+ Squeal.PostgreSQL.Query.From: instance GHC.Show.Show (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
+ Squeal.PostgreSQL.Query.From: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
+ Squeal.PostgreSQL.Query.From: instance Squeal.PostgreSQL.Type.List.Additional (Squeal.PostgreSQL.Query.From.FromClause lat with db params)
+ Squeal.PostgreSQL.Query.From: newtype FromClause (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
+ Squeal.PostgreSQL.Query.From: subquery :: Aliased (Query lat with db params) query -> FromClause lat with db params '[query]
+ Squeal.PostgreSQL.Query.From: table :: (Has sch db schema, Has tab schema ( 'Table table)) => Aliased (QualifiedAlias sch) (alias ::: tab) -> FromClause lat with db params '[alias ::: TableToRow table]
+ Squeal.PostgreSQL.Query.From: view :: (Has sch db schema, Has vw schema ( 'View view)) => Aliased (QualifiedAlias sch) (alias ::: vw) -> FromClause lat with db params '[alias ::: view]
+ Squeal.PostgreSQL.Query.From.Join: [JoinFunctionN] :: SListI args => SetFunN db args set -> NP (Expression 'Ungrouped lat with db params left) args -> JoinItem lat with db params left '[set]
+ Squeal.PostgreSQL.Query.From.Join: [JoinFunction] :: SetFun db arg set -> Expression 'Ungrouped lat with db params left arg -> JoinItem lat with db params left '[set]
+ Squeal.PostgreSQL.Query.From.Join: [JoinLateral] :: Aliased (Query (Join lat left) with db params) query -> JoinItem lat with db params left '[query]
+ Squeal.PostgreSQL.Query.From.Join: [Join] :: FromClause lat with db params right -> JoinItem lat with db params left right
+ Squeal.PostgreSQL.Query.From.Join: cross :: JoinItem lat with db params left right -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
+ Squeal.PostgreSQL.Query.From.Join: crossJoin :: FromClause lat with db params right -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
+ Squeal.PostgreSQL.Query.From.Join: crossJoinLateral :: Aliased (Query (Join lat left) with db params) query -> FromClause lat with db params left -> FromClause lat with db params (Join left '[query])
+ Squeal.PostgreSQL.Query.From.Join: data JoinItem (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (left :: FromType) (right :: FromType)
+ Squeal.PostgreSQL.Query.From.Join: fullOuter :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (NullifyFrom (Join left right))
+ Squeal.PostgreSQL.Query.From.Join: fullOuterJoin :: FromClause lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (NullifyFrom (Join left right))
+ Squeal.PostgreSQL.Query.From.Join: fullOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (NullifyFrom (Join left '[query]))
+ Squeal.PostgreSQL.Query.From.Join: inner :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
+ Squeal.PostgreSQL.Query.From.Join: innerJoin :: FromClause lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
+ Squeal.PostgreSQL.Query.From.Join: innerJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (Join left '[query])
+ Squeal.PostgreSQL.Query.From.Join: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.From.Join.JoinItem lat with db params left right)
+ Squeal.PostgreSQL.Query.From.Join: leftOuter :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left (NullifyFrom right))
+ Squeal.PostgreSQL.Query.From.Join: leftOuterJoin :: FromClause lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left (NullifyFrom right))
+ Squeal.PostgreSQL.Query.From.Join: leftOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (Join left (NullifyFrom '[query]))
+ Squeal.PostgreSQL.Query.From.Join: rightOuter :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join (NullifyFrom left) right)
+ Squeal.PostgreSQL.Query.From.Join: rightOuterJoin :: FromClause lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join (NullifyFrom left) right)
+ Squeal.PostgreSQL.Query.From.Join: rightOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (Join (NullifyFrom left) '[query])
+ Squeal.PostgreSQL.Query.From.Set: generateSeries :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric] => '[null ty, null ty] --|-> ("generate_series" ::: '["generate_series" ::: null ty])
+ Squeal.PostgreSQL.Query.From.Set: generateSeriesStep :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric] => '[null ty, null ty, null ty] --|-> ("generate_series" ::: '["generate_series" ::: null ty])
+ Squeal.PostgreSQL.Query.From.Set: generateSeriesTimestamp :: ty `In` '[ 'PGtimestamp, 'PGtimestamptz] => '[null ty, null ty, null 'PGinterval] --|-> ("generate_series" ::: '["generate_series" ::: null ty])
+ Squeal.PostgreSQL.Query.From.Set: setFunction :: (Has sch db schema, Has fun schema ( 'Function ('[ty] :=> 'ReturnsTable row))) => QualifiedAlias sch fun -> SetFun db ty (fun ::: row)
+ Squeal.PostgreSQL.Query.From.Set: setFunctionN :: (Has sch db schema, Has fun schema ( 'Function (tys :=> 'ReturnsTable row)), SListI tys) => QualifiedAlias sch fun -> SetFunN db tys (fun ::: row)
+ Squeal.PostgreSQL.Query.From.Set: type (--|->) arg set = forall db. SetFunN db arg set " output"
+ Squeal.PostgreSQL.Query.From.Set: type SetFun db arg row = forall lat with params. Expression 'Ungrouped lat with db params '[] arg " input" -> FromClause lat with db params '[row] " output"
+ Squeal.PostgreSQL.Query.From.Set: type SetFunN db args set = forall lat with params. NP (Expression 'Ungrouped lat with db params '[]) args " input" -> FromClause lat with db params '[set] " output"
+ Squeal.PostgreSQL.Query.From.Set: unsafeSetFunction :: forall fun ty row. KnownSymbol fun => ByteString -> ty -|-> (fun ::: row)
+ Squeal.PostgreSQL.Query.From.Set: unsafeSetFunctionN :: forall fun tys row. (SListI tys, KnownSymbol fun) => ByteString -> tys --|-> (fun ::: row)
+ Squeal.PostgreSQL.Query.Select: [Also] :: Selection grp lat with db params from right -> Selection grp lat with db params from left -> Selection grp lat with db params from (Join left right)
+ Squeal.PostgreSQL.Query.Select: [DotStar] :: Has tab from row => Alias tab -> Selection 'Ungrouped lat with db params from row
+ Squeal.PostgreSQL.Query.Select: [List] :: SListI row => NP (Aliased (Expression grp lat with db params from)) row -> Selection grp lat with db params from row
+ Squeal.PostgreSQL.Query.Select: [Over] :: SListI row => NP (Aliased (WindowFunction grp lat with db params from)) row -> WindowDefinition grp lat with db params from -> Selection grp lat with db params from row
+ Squeal.PostgreSQL.Query.Select: [Star] :: HasUnique tab from row => Selection 'Ungrouped lat with db params from row
+ Squeal.PostgreSQL.Query.Select: data Selection grp lat with db params from row
+ Squeal.PostgreSQL.Query.Select: instance (GHC.TypeLits.KnownSymbol col, row Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.Aliasable col (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from row)
+ Squeal.PostgreSQL.Query.Select: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Query.Select.Selection 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from row1)
+ Squeal.PostgreSQL.Query.Select: instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty], Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Query.Select.Selection ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from row1)
+ Squeal.PostgreSQL.Query.Select: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Select.Selection 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from row1)
+ Squeal.PostgreSQL.Query.Select: instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty], Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Select.Selection ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from row1)
+ Squeal.PostgreSQL.Query.Select: instance Data.String.IsString (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from '["fromOnly" Squeal.PostgreSQL.Type.Alias.::: 'Squeal.PostgreSQL.Type.Schema.NotNull 'Squeal.PostgreSQL.Type.Schema.PGtext])
+ Squeal.PostgreSQL.Query.Select: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from row)
+ Squeal.PostgreSQL.Query.Select: instance Squeal.PostgreSQL.Type.List.Additional (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from)
+ Squeal.PostgreSQL.Query.Select: select :: (SListI row, row ~ (x : xs)) => Selection grp lat with db params from row -> TableExpression grp lat with db params from -> Query lat with db params row
+ Squeal.PostgreSQL.Query.Select: selectDistinct :: (SListI columns, columns ~ (col : cols)) => Selection grp lat with db params from columns -> TableExpression grp lat with db params from -> Query lat with db params columns
+ Squeal.PostgreSQL.Query.Select: selectDistinctOn :: (SListI columns, columns ~ (col : cols)) => [SortExpression grp lat with db params from] -> Selection grp lat with db params from columns -> TableExpression grp lat with db params from -> Query lat with db params columns
+ Squeal.PostgreSQL.Query.Select: selectDistinctOn_ :: (SListI columns, columns ~ (col : cols)) => [SortExpression grp lat with db params from] -> NP (Aliased (Expression grp lat with db params from)) columns -> TableExpression grp lat with db params from -> Query lat with db params columns
+ Squeal.PostgreSQL.Query.Select: selectDistinct_ :: (SListI columns, columns ~ (col : cols)) => NP (Aliased (Expression grp lat with db params from)) columns -> TableExpression grp lat with db params from -> Query lat with db params columns
+ Squeal.PostgreSQL.Query.Select: select_ :: (SListI row, row ~ (x : xs)) => NP (Aliased (Expression grp lat with db params from)) row -> TableExpression grp lat with db params from -> Query lat with db params row
+ Squeal.PostgreSQL.Query.Table: TableExpression :: FromClause lat with db params from -> [Condition 'Ungrouped lat with db params from] -> GroupByClause grp from -> HavingClause grp lat with db params from -> [SortExpression grp lat with db params from] -> [Word64] -> [Word64] -> TableExpression
+ Squeal.PostgreSQL.Query.Table: UnsafeGroupByClause :: ByteString -> GroupByClause grp from
+ Squeal.PostgreSQL.Query.Table: [By1] :: (HasUnique table from columns, Has column columns ty) => Alias column -> By from '(table, column)
+ Squeal.PostgreSQL.Query.Table: [By2] :: (Has table from columns, Has column columns ty) => Alias table -> Alias column -> By from '(table, column)
+ Squeal.PostgreSQL.Query.Table: [Having] :: [Condition ( 'Grouped bys) lat with db params from] -> HavingClause ( 'Grouped bys) lat with db params from
+ Squeal.PostgreSQL.Query.Table: [NoHaving] :: HavingClause 'Ungrouped lat with db params from
+ Squeal.PostgreSQL.Query.Table: [fromClause] :: TableExpression -> FromClause lat with db params from
+ Squeal.PostgreSQL.Query.Table: [groupByClause] :: TableExpression -> GroupByClause grp from
+ Squeal.PostgreSQL.Query.Table: [havingClause] :: TableExpression -> HavingClause grp lat with db params from
+ Squeal.PostgreSQL.Query.Table: [limitClause] :: TableExpression -> [Word64]
+ Squeal.PostgreSQL.Query.Table: [offsetClause] :: TableExpression -> [Word64]
+ Squeal.PostgreSQL.Query.Table: [orderByClause] :: TableExpression -> [SortExpression grp lat with db params from]
+ Squeal.PostgreSQL.Query.Table: [renderGroupByClause] :: GroupByClause grp from -> ByteString
+ Squeal.PostgreSQL.Query.Table: [whereClause] :: TableExpression -> [Condition 'Ungrouped lat with db params from]
+ Squeal.PostgreSQL.Query.Table: data By (from :: FromType) (by :: (Symbol, Symbol))
+ Squeal.PostgreSQL.Query.Table: data HavingClause grp lat with db params from
+ Squeal.PostgreSQL.Query.Table: data TableExpression (grp :: Grouping) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
+ Squeal.PostgreSQL.Query.Table: from :: FromClause lat with db params from -> TableExpression 'Ungrouped lat with db params from
+ Squeal.PostgreSQL.Query.Table: groupBy :: SListI bys => NP (By from) bys -> TableExpression 'Ungrouped lat with db params from -> TableExpression ( 'Grouped bys) lat with db params from
+ Squeal.PostgreSQL.Query.Table: having :: Condition ( 'Grouped bys) lat with db params from -> TableExpression ( 'Grouped bys) lat with db params from -> TableExpression ( 'Grouped bys) lat with db params from
+ Squeal.PostgreSQL.Query.Table: instance (Squeal.PostgreSQL.Type.Alias.Has rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, by Data.Type.Equality.~ '(rel, col)) => Squeal.PostgreSQL.Type.Alias.IsQualified rel col (Squeal.PostgreSQL.Query.Table.By rels by)
+ Squeal.PostgreSQL.Query.Table: instance (Squeal.PostgreSQL.Type.Alias.Has rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, bys Data.Type.Equality.~ '[ '(rel, col)]) => Squeal.PostgreSQL.Type.Alias.IsQualified rel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Query.Table.By rels) bys)
+ Squeal.PostgreSQL.Query.Table: instance (Squeal.PostgreSQL.Type.Alias.HasUnique rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, by Data.Type.Equality.~ '(rel, col)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Table.By rels by)
+ Squeal.PostgreSQL.Query.Table: instance (Squeal.PostgreSQL.Type.Alias.HasUnique rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, bys Data.Type.Equality.~ '[ '(rel, col)]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Query.Table.By rels) bys)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Table.By from by)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Table.By from by)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.Table.TableExpression grp lat with db params from)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Show.Show (Squeal.PostgreSQL.Query.Table.By from by)
+ Squeal.PostgreSQL.Query.Table: instance GHC.Show.Show (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
+ Squeal.PostgreSQL.Query.Table: instance Squeal.PostgreSQL.Expression.Sort.OrderBy (Squeal.PostgreSQL.Query.Table.TableExpression grp) grp
+ Squeal.PostgreSQL.Query.Table: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.By from by)
+ Squeal.PostgreSQL.Query.Table: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
+ Squeal.PostgreSQL.Query.Table: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.TableExpression grp lat with db params from)
+ Squeal.PostgreSQL.Query.Table: instance forall k1 (grp :: k1) k2 (from :: k2). Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
+ Squeal.PostgreSQL.Query.Table: instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Classes.Eq (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
+ Squeal.PostgreSQL.Query.Table: instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Classes.Ord (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
+ Squeal.PostgreSQL.Query.Table: instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Generics.Generic (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
+ Squeal.PostgreSQL.Query.Table: instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Show.Show (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
+ Squeal.PostgreSQL.Query.Table: instance forall k1 k2 (grp :: k2) (from :: k1). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
+ Squeal.PostgreSQL.Query.Table: limit :: Word64 -> TableExpression grp lat with db params from -> TableExpression grp lat with db params from
+ Squeal.PostgreSQL.Query.Table: newtype GroupByClause grp from
+ Squeal.PostgreSQL.Query.Table: offset :: Word64 -> TableExpression grp lat with db params from -> TableExpression grp lat with db params from
+ Squeal.PostgreSQL.Query.Table: where_ :: Condition 'Ungrouped lat with db params from -> TableExpression grp lat with db params from -> TableExpression grp lat with db params from
+ Squeal.PostgreSQL.Query.Values: values :: SListI cols => NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols -> [NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols] -> Query lat with db params cols
+ Squeal.PostgreSQL.Query.Values: values_ :: SListI cols => NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols -> Query lat with db params cols
+ Squeal.PostgreSQL.Query.With: [CommonTableExpression] :: Aliased (statement with db params) (cte ::: common) -> CommonTableExpression statement db params with ((cte ::: common) : with)
+ Squeal.PostgreSQL.Query.With: class With statement
+ Squeal.PostgreSQL.Query.With: data CommonTableExpression statement (db :: SchemasType) (params :: [NullType]) (with0 :: FromType) (with1 :: FromType)
+ Squeal.PostgreSQL.Query.With: instance (GHC.TypeLits.KnownSymbol cte, with1 Data.Type.Equality.~ ((cte Squeal.PostgreSQL.Type.Alias.::: common) : with)) => Squeal.PostgreSQL.Type.Alias.Aliasable cte (statement with db params common) (Control.Category.Free.Path (Squeal.PostgreSQL.Query.With.CommonTableExpression statement db params) with with1)
+ Squeal.PostgreSQL.Query.With: instance (GHC.TypeLits.KnownSymbol cte, with1 Data.Type.Equality.~ ((cte Squeal.PostgreSQL.Type.Alias.::: common) : with)) => Squeal.PostgreSQL.Type.Alias.Aliasable cte (statement with db params common) (Squeal.PostgreSQL.Query.With.CommonTableExpression statement db params with with1)
+ Squeal.PostgreSQL.Query.With: instance (forall (c :: Squeal.PostgreSQL.Type.Schema.FromType) (s :: Squeal.PostgreSQL.Type.Schema.SchemasType) (p :: [Squeal.PostgreSQL.Type.Schema.NullType]) (r :: Squeal.PostgreSQL.Type.Schema.RowType). Squeal.PostgreSQL.Render.RenderSQL (statement c s p r)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.With.CommonTableExpression statement db params with0 with1)
+ Squeal.PostgreSQL.Query.With: instance Squeal.PostgreSQL.Query.With.With (Squeal.PostgreSQL.Query.Query lat)
+ Squeal.PostgreSQL.Query.With: with :: With statement => Path (CommonTableExpression statement db params) with0 with1 -> statement with1 db params row -> statement with0 db params row
+ Squeal.PostgreSQL.Query.With: withRecursive :: Aliased (Query lat (recursive : with) db params) recursive -> Query lat (recursive : with) db params row -> Query lat with db params row
+ Squeal.PostgreSQL.Render: escapeQuotedString :: String -> ByteString
+ Squeal.PostgreSQL.Render: escapeQuotedText :: Text -> ByteString
+ Squeal.PostgreSQL.Session: PQ :: (K Connection db0 -> m (K x db1)) -> PQ
+ Squeal.PostgreSQL.Session: [unPQ] :: PQ -> K Connection db0 -> m (K x db1)
+ Squeal.PostgreSQL.Session: evalPQ :: Functor m => PQ db0 db1 m x -> K Connection db0 -> m x
+ Squeal.PostgreSQL.Session: execPQ :: Functor m => PQ db0 db1 m x -> K Connection db0 -> m (K Connection db1)
+ Squeal.PostgreSQL.Session: instance (Control.Monad.IO.Class.MonadIO io, db0 Data.Type.Equality.~ db, db1 Data.Type.Equality.~ db) => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Squeal.PostgreSQL.Session.PQ db0 db1 io)
+ Squeal.PostgreSQL.Session: instance (Control.Monad.IO.Class.MonadIO m, schema0 Data.Type.Equality.~ schema1) => Control.Monad.IO.Class.MonadIO (Squeal.PostgreSQL.Session.PQ schema0 schema1 m)
+ Squeal.PostgreSQL.Session: instance (Control.Monad.IO.Unlift.MonadUnliftIO m, db0 Data.Type.Equality.~ db1) => Control.Monad.IO.Unlift.MonadUnliftIO (Squeal.PostgreSQL.Session.PQ db0 db1 m)
+ Squeal.PostgreSQL.Session: instance (GHC.Base.Monad m, GHC.Base.Monoid r, db0 Data.Type.Equality.~ db1) => GHC.Base.Monoid (Squeal.PostgreSQL.Session.PQ db0 db1 m r)
+ Squeal.PostgreSQL.Session: instance (GHC.Base.Monad m, GHC.Base.Semigroup r, db0 Data.Type.Equality.~ db1) => GHC.Base.Semigroup (Squeal.PostgreSQL.Session.PQ db0 db1 m r)
+ Squeal.PostgreSQL.Session: instance (GHC.Base.Monad m, db0 Data.Type.Equality.~ db1) => Control.Monad.Fail.MonadFail (Squeal.PostgreSQL.Session.PQ db0 db1 m)
+ Squeal.PostgreSQL.Session: instance (GHC.Base.Monad m, db0 Data.Type.Equality.~ db1) => GHC.Base.Applicative (Squeal.PostgreSQL.Session.PQ db0 db1 m)
+ Squeal.PostgreSQL.Session: instance (GHC.Base.Monad m, db0 Data.Type.Equality.~ db1) => GHC.Base.Monad (Squeal.PostgreSQL.Session.PQ db0 db1 m)
+ Squeal.PostgreSQL.Session: instance (db0 Data.Type.Equality.~ db1) => Control.Monad.Morph.MFunctor (Squeal.PostgreSQL.Session.PQ db0 db1)
+ Squeal.PostgreSQL.Session: instance (db0 Data.Type.Equality.~ db1) => Control.Monad.Morph.MMonad (Squeal.PostgreSQL.Session.PQ db0 db1)
+ Squeal.PostgreSQL.Session: instance (db0 Data.Type.Equality.~ db1) => Control.Monad.Trans.Class.MonadTrans (Squeal.PostgreSQL.Session.PQ db0 db1)
+ Squeal.PostgreSQL.Session: instance GHC.Base.Monad m => GHC.Base.Functor (Squeal.PostgreSQL.Session.PQ db0 db1 m)
+ Squeal.PostgreSQL.Session: instance Squeal.PostgreSQL.Session.Indexed.IndexedMonadTrans Squeal.PostgreSQL.Session.PQ
+ Squeal.PostgreSQL.Session: instance Squeal.PostgreSQL.Session.Indexed.IndexedMonadTransPQ Squeal.PostgreSQL.Session.PQ
+ Squeal.PostgreSQL.Session: newtype PQ (db0 :: SchemasType) (db1 :: SchemasType) (m :: Type -> Type) (x :: Type)
+ Squeal.PostgreSQL.Session: runPQ :: Functor m => PQ db0 db1 m x -> K Connection db0 -> m (x, K Connection db1)
+ Squeal.PostgreSQL.Session: withConnection :: forall db0 db1 io x. MonadUnliftIO io => ByteString -> PQ db0 db1 io x -> io x
+ Squeal.PostgreSQL.Session.Connection: K :: a -> K a
+ Squeal.PostgreSQL.Session.Connection: connectdb :: forall (db :: SchemasType) io. MonadIO io => ByteString -> io (K Connection db)
+ Squeal.PostgreSQL.Session.Connection: data Connection
+ Squeal.PostgreSQL.Session.Connection: finish :: MonadIO io => K Connection db -> io ()
+ Squeal.PostgreSQL.Session.Connection: lowerConnection :: K Connection (schema : db) -> K Connection db
+ Squeal.PostgreSQL.Session.Connection: newtype K a (b :: k) :: forall k. () => Type -> k -> Type
+ Squeal.PostgreSQL.Session.Connection: unK :: () => K a b -> a
+ Squeal.PostgreSQL.Session.Decode: DecodeRow :: ReaderT (NP (K (Maybe ByteString)) row) (Except Text) y -> DecodeRow
+ Squeal.PostgreSQL.Session.Decode: ExceptT :: m (Either e a) -> ExceptT e a
+ Squeal.PostgreSQL.Session.Decode: StateT :: (s -> m (a, s)) -> StateT s a
+ Squeal.PostgreSQL.Session.Decode: [runStateT] :: StateT s a -> s -> m (a, s)
+ Squeal.PostgreSQL.Session.Decode: [unDecodeRow] :: DecodeRow -> ReaderT (NP (K (Maybe ByteString)) row) (Except Text) y
+ Squeal.PostgreSQL.Session.Decode: class FromArray (dims :: [Nat]) (ty :: NullType) (y :: Type)
+ Squeal.PostgreSQL.Session.Decode: class FromField (field :: (Symbol, NullType)) (y :: (Symbol, Type))
+ Squeal.PostgreSQL.Session.Decode: class IsPG y => FromPG y
+ Squeal.PostgreSQL.Session.Decode: class FromValue (ty :: NullType) (y :: Type)
+ Squeal.PostgreSQL.Session.Decode: decodeRow :: (NP (K (Maybe ByteString)) row -> Either Text y) -> DecodeRow row y
+ Squeal.PostgreSQL.Session.Decode: devalue :: Value x -> StateT ByteString (Except Text) x
+ Squeal.PostgreSQL.Session.Decode: fromArray :: FromArray dims ty y => Array y
+ Squeal.PostgreSQL.Session.Decode: fromField :: FromField field y => Maybe ByteString -> Either Text (P y)
+ Squeal.PostgreSQL.Session.Decode: fromPG :: FromPG y => StateT ByteString (Except Text) y
+ Squeal.PostgreSQL.Session.Decode: fromValue :: FromValue ty y => Maybe ByteString -> Either Text y
+ Squeal.PostgreSQL.Session.Decode: genericRow :: forall row y ys. (IsRecord y ys, AllZip FromField row ys) => DecodeRow row y
+ Squeal.PostgreSQL.Session.Decode: instance (Generics.SOP.Record.IsRecord y ys, Data.SOP.Constraint.AllZip Squeal.PostgreSQL.Session.Decode.FromField row ys, Squeal.PostgreSQL.Type.PG.RowPG y Data.Type.Equality.~ row) => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.Composite y)
+ Squeal.PostgreSQL.Session.Decode: instance (Generics.SOP.Universe.IsEnumType y, Generics.SOP.Universe.HasDatatypeInfo y, Squeal.PostgreSQL.Type.PG.LabelsPG y Data.Type.Equality.~ labels) => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.Enumerated y)
+ Squeal.PostgreSQL.Session.Decode: instance (Generics.SOP.Universe.IsProductType product ys, Squeal.PostgreSQL.Type.List.Length ys Data.Type.Equality.~ dim, Data.SOP.Constraint.All ((Data.Type.Equality.~) y) ys, Squeal.PostgreSQL.Session.Decode.FromArray dims ty y) => Squeal.PostgreSQL.Session.Decode.FromArray (dim : dims) ty product
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromArray '[] ty y, ty Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.NullPG y) => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector y))
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromArray '[] ty y, ty Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.NullPG y) => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.VarArray [y])
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromPG y, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG y) => Squeal.PostgreSQL.Session.Decode.FromArray '[] ('Squeal.PostgreSQL.Type.Schema.NotNull pg) y
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromPG y, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG y) => Squeal.PostgreSQL.Session.Decode.FromArray '[] ('Squeal.PostgreSQL.Type.Schema.Null pg) (GHC.Maybe.Maybe y)
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromPG y, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG y) => Squeal.PostgreSQL.Session.Decode.FromValue ('Squeal.PostgreSQL.Type.Schema.NotNull pg) y
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromPG y, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG y) => Squeal.PostgreSQL.Session.Decode.FromValue ('Squeal.PostgreSQL.Type.Schema.Null pg) (GHC.Maybe.Maybe y)
+ Squeal.PostgreSQL.Session.Decode: instance (Squeal.PostgreSQL.Session.Decode.FromValue ty y, fld0 Data.Type.Equality.~ fld1) => Squeal.PostgreSQL.Session.Decode.FromField (fld0 Squeal.PostgreSQL.Type.Alias.::: ty) (fld1 Squeal.PostgreSQL.Type.Alias.::: y)
+ Squeal.PostgreSQL.Session.Decode: instance Control.Monad.Error.Class.MonadError Data.Text.Internal.Text (Squeal.PostgreSQL.Session.Decode.DecodeRow row)
+ Squeal.PostgreSQL.Session.Decode: instance Data.Aeson.Types.FromJSON.FromJSON x => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.Json x)
+ Squeal.PostgreSQL.Session.Decode: instance Data.Aeson.Types.FromJSON.FromJSON x => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.Jsonb x)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.Base.Alternative (Squeal.PostgreSQL.Session.Decode.DecodeRow row)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.Base.Applicative (Squeal.PostgreSQL.Session.Decode.DecodeRow row)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.Base.Functor (Squeal.PostgreSQL.Session.Decode.DecodeRow row)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.Base.Monad (Squeal.PostgreSQL.Session.Decode.DecodeRow row)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.Base.MonadPlus (Squeal.PostgreSQL.Session.Decode.DecodeRow row)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.OverloadedLabels.IsLabel fld (Control.Monad.Trans.Maybe.MaybeT (Squeal.PostgreSQL.Session.Decode.DecodeRow row) y) => GHC.OverloadedLabels.IsLabel fld (Control.Monad.Trans.Maybe.MaybeT (Squeal.PostgreSQL.Session.Decode.DecodeRow (field : row)) y)
+ Squeal.PostgreSQL.Session.Decode: instance GHC.OverloadedLabels.IsLabel fld (Squeal.PostgreSQL.Session.Decode.DecodeRow row y) => GHC.OverloadedLabels.IsLabel fld (Squeal.PostgreSQL.Session.Decode.DecodeRow (field : row) y)
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromArray dims ty y => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Type.FixArray y)
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone)
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG (Network.IP.Addr.NetAddr Network.IP.Addr.IP)
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Aeson.Types.Internal.Value
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.ByteString.Internal.ByteString
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.ByteString.Lazy.Internal.ByteString
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Scientific.Scientific
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Text.Internal.Lazy.Text
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Text.Internal.Text
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Time.Calendar.Days.Day
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Time.Clock.Internal.DiffTime.DiffTime
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Time.Clock.Internal.UTCTime.UTCTime
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Data.UUID.Types.Internal.UUID
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Database.PostgreSQL.LibPQ.Oid
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Base.String
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Int.Int16
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Int.Int32
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Int.Int64
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Types.Bool
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Types.Char
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Types.Double
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG GHC.Types.Float
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromPG y => Squeal.PostgreSQL.Session.Decode.FromPG (Squeal.PostgreSQL.Expression.Range.Range y)
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromValue ty (GHC.Maybe.Maybe y) => GHC.OverloadedLabels.IsLabel fld (Control.Monad.Trans.Maybe.MaybeT (Squeal.PostgreSQL.Session.Decode.DecodeRow ((fld Squeal.PostgreSQL.Type.Alias.::: ty) : row)) y)
+ Squeal.PostgreSQL.Session.Decode: instance Squeal.PostgreSQL.Session.Decode.FromValue ty y => GHC.OverloadedLabels.IsLabel fld (Squeal.PostgreSQL.Session.Decode.DecodeRow ((fld Squeal.PostgreSQL.Type.Alias.::: ty) : row) y)
+ Squeal.PostgreSQL.Session.Decode: newtype DecodeRow (row :: RowType) (y :: Type)
+ Squeal.PostgreSQL.Session.Decode: newtype ExceptT e (m :: Type -> Type) a
+ Squeal.PostgreSQL.Session.Decode: newtype StateT s (m :: Type -> Type) a
+ Squeal.PostgreSQL.Session.Decode: rowValue :: (PG y ~ 'PGcomposite row, SListI row) => DecodeRow row y -> StateT ByteString (Except Text) y
+ Squeal.PostgreSQL.Session.Decode: runDecodeRow :: DecodeRow row y -> NP (K (Maybe ByteString)) row -> Either Text y
+ Squeal.PostgreSQL.Session.Encode: (*.) :: forall db x x0 ty0 x1 ty1. (ToParam db ty0 x0, ToParam db ty1 x1) => (x -> x0) -> (x -> x1) -> EncodeParams db '[ty0, ty1] x
+ Squeal.PostgreSQL.Session.Encode: (.*) :: forall db x0 ty x tys. ToParam db ty x0 => (x -> x0) -> EncodeParams db tys x -> EncodeParams db (ty : tys) x
+ Squeal.PostgreSQL.Session.Encode: EncodeParams :: (x -> ReaderT (K Connection db) IO (NP (K (Maybe Encoding)) tys)) -> EncodeParams
+ Squeal.PostgreSQL.Session.Encode: [runEncodeParams] :: EncodeParams -> x -> ReaderT (K Connection db) IO (NP (K (Maybe Encoding)) tys)
+ Squeal.PostgreSQL.Session.Encode: aParam :: forall db x. ToParam db (NullPG x) x => EncodeParams db '[NullPG x] x
+ Squeal.PostgreSQL.Session.Encode: appendParams :: EncodeParams db params0 x -> EncodeParams db params1 x -> EncodeParams db (Join params0 params1) x
+ Squeal.PostgreSQL.Session.Encode: arrayDims :: ToArray db dims ty x => [Int32]
+ Squeal.PostgreSQL.Session.Encode: arrayNulls :: ToArray db dims ty x => Bool
+ Squeal.PostgreSQL.Session.Encode: arrayPayload :: ToArray db dims ty x => x -> ReaderT (K Connection db) IO Encoding
+ Squeal.PostgreSQL.Session.Encode: class ToArray (db :: SchemasType) (dims :: [Nat]) (ty :: NullType) (x :: Type)
+ Squeal.PostgreSQL.Session.Encode: class ToField (db :: SchemasType) (field :: (Symbol, NullType)) (x :: (Symbol, Type))
+ Squeal.PostgreSQL.Session.Encode: class IsPG x => ToPG (db :: SchemasType) (x :: Type)
+ Squeal.PostgreSQL.Session.Encode: class ToParam (db :: SchemasType) (ty :: NullType) (x :: Type)
+ Squeal.PostgreSQL.Session.Encode: genericParams :: forall db params x xs. (IsProductType x xs, AllZip (ToParam db) params xs) => EncodeParams db params x
+ Squeal.PostgreSQL.Session.Encode: infixl 8 *.
+ Squeal.PostgreSQL.Session.Encode: infixr 5 .*
+ Squeal.PostgreSQL.Session.Encode: instance (Data.SOP.Constraint.SListI fields, Generics.SOP.Record.IsRecord x xs, Data.SOP.Constraint.AllZip (Squeal.PostgreSQL.Session.Encode.ToField db) fields xs, Data.SOP.Constraint.All (Squeal.PostgreSQL.Session.Oid.OidOfField db) fields, Squeal.PostgreSQL.Type.PG.RowPG x Data.Type.Equality.~ fields) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Composite x)
+ Squeal.PostgreSQL.Session.Encode: instance (Generics.SOP.Universe.IsEnumType x, Generics.SOP.Universe.HasDatatypeInfo x, Squeal.PostgreSQL.Type.PG.LabelsPG x Data.Type.Equality.~ labels) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Enumerated x)
+ Squeal.PostgreSQL.Session.Encode: instance (Generics.SOP.Universe.IsProductType tuple xs, Squeal.PostgreSQL.Type.List.Length xs Data.Type.Equality.~ dim, Data.SOP.Constraint.All ((Data.Type.Equality.~) x) xs, Squeal.PostgreSQL.Session.Encode.ToArray db dims ty x, GHC.TypeNats.KnownNat dim) => Squeal.PostgreSQL.Session.Encode.ToArray db (dim : dims) ty tuple
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Session.Encode.ToArray db dims ty x, Squeal.PostgreSQL.Session.Oid.OidOfNull db ty) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.FixArray x)
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToArray db '[] ('Squeal.PostgreSQL.Type.Schema.NotNull pg) x
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToArray db '[] ('Squeal.PostgreSQL.Type.Schema.Null pg) (GHC.Maybe.Maybe x)
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToParam db ('Squeal.PostgreSQL.Type.Schema.NotNull pg) x
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToParam db ('Squeal.PostgreSQL.Type.Schema.Null pg) (GHC.Maybe.Maybe x)
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Type.PG.NullPG x Data.Type.Equality.~ ty, Squeal.PostgreSQL.Session.Encode.ToArray db '[] ty x, Squeal.PostgreSQL.Session.Oid.OidOfNull db ty) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector x))
+ Squeal.PostgreSQL.Session.Encode: instance (Squeal.PostgreSQL.Type.PG.NullPG x Data.Type.Equality.~ ty, Squeal.PostgreSQL.Session.Encode.ToArray db '[] ty x, Squeal.PostgreSQL.Session.Oid.OidOfNull db ty) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.VarArray [x])
+ Squeal.PostgreSQL.Session.Encode: instance (fld0 Data.Type.Equality.~ fld1, Squeal.PostgreSQL.Session.Encode.ToParam db ty x) => Squeal.PostgreSQL.Session.Encode.ToField db (fld0 Squeal.PostgreSQL.Type.Alias.::: ty) (fld1 Squeal.PostgreSQL.Type.Alias.::: x)
+ Squeal.PostgreSQL.Session.Encode: instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Json x)
+ Squeal.PostgreSQL.Session.Encode: instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Jsonb x)
+ Squeal.PostgreSQL.Session.Encode: instance Data.Functor.Contravariant.Contravariant (Squeal.PostgreSQL.Session.Encode.EncodeParams db tys)
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone)
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db (Network.IP.Addr.NetAddr Network.IP.Addr.IP)
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Aeson.Types.Internal.Value
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.ByteString.Internal.ByteString
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.ByteString.Lazy.Internal.ByteString
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Scientific.Scientific
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Text.Internal.Lazy.Text
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Text.Internal.Text
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.Calendar.Days.Day
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.Clock.Internal.DiffTime.DiffTime
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.Clock.Internal.UTCTime.UTCTime
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.UUID.Types.Internal.UUID
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Database.PostgreSQL.LibPQ.Oid
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Base.String
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Int.Int16
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Int.Int32
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Int.Int64
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Bool
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Char
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Double
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Float
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Session.Encode: instance Squeal.PostgreSQL.Session.Encode.ToPG db x => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Expression.Range.Range x)
+ Squeal.PostgreSQL.Session.Encode: newtype EncodeParams (db :: SchemasType) (tys :: [NullType]) (x :: Type)
+ Squeal.PostgreSQL.Session.Encode: nilParams :: EncodeParams db '[] x
+ Squeal.PostgreSQL.Session.Encode: toField :: ToField db field x => P x -> ReaderT (K Connection db) IO (K (Maybe Encoding) field)
+ Squeal.PostgreSQL.Session.Encode: toPG :: ToPG db x => x -> ReaderT (K Connection db) IO Encoding
+ Squeal.PostgreSQL.Session.Encode: toParam :: ToParam db ty x => x -> ReaderT (K Connection db) IO (Maybe Encoding)
+ Squeal.PostgreSQL.Session.Exception: BadResponse :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: ColumnsException :: Text -> Column -> SquealException
+ Squeal.PostgreSQL.Session.Exception: CommandOk :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: ConnectionException :: Text -> SquealException
+ Squeal.PostgreSQL.Session.Exception: CopyBoth :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: CopyIn :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: CopyOut :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: DecodingException :: Text -> Text -> SquealException
+ Squeal.PostgreSQL.Session.Exception: EmptyQuery :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: FatalError :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: NonfatalError :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: RowsException :: Text -> Row -> Row -> SquealException
+ Squeal.PostgreSQL.Session.Exception: SQLException :: SQLState -> SquealException
+ Squeal.PostgreSQL.Session.Exception: SQLState :: ExecStatus -> ByteString -> ByteString -> SQLState
+ Squeal.PostgreSQL.Session.Exception: SingleTuple :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: TuplesOk :: ExecStatus
+ Squeal.PostgreSQL.Session.Exception: [sqlErrorMessage] :: SQLState -> ByteString
+ Squeal.PostgreSQL.Session.Exception: [sqlExecStatus] :: SQLState -> ExecStatus
+ Squeal.PostgreSQL.Session.Exception: [sqlStateCode] :: SQLState -> ByteString
+ Squeal.PostgreSQL.Session.Exception: catchSqueal :: MonadUnliftIO io => io a -> (SquealException -> io a) -> io a
+ Squeal.PostgreSQL.Session.Exception: data ExecStatus
+ Squeal.PostgreSQL.Session.Exception: data SQLState
+ Squeal.PostgreSQL.Session.Exception: data SquealException
+ Squeal.PostgreSQL.Session.Exception: handleSqueal :: MonadUnliftIO io => (SquealException -> io a) -> io a -> io a
+ Squeal.PostgreSQL.Session.Exception: instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Exception.SQLState
+ Squeal.PostgreSQL.Session.Exception: instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Exception.SquealException
+ Squeal.PostgreSQL.Session.Exception: instance GHC.Exception.Type.Exception Squeal.PostgreSQL.Session.Exception.SquealException
+ Squeal.PostgreSQL.Session.Exception: instance GHC.Show.Show Squeal.PostgreSQL.Session.Exception.SQLState
+ Squeal.PostgreSQL.Session.Exception: instance GHC.Show.Show Squeal.PostgreSQL.Session.Exception.SquealException
+ Squeal.PostgreSQL.Session.Exception: pattern CheckViolation :: ByteString -> SquealException
+ Squeal.PostgreSQL.Session.Exception: pattern SerializationFailure :: ByteString -> SquealException
+ Squeal.PostgreSQL.Session.Exception: pattern UniqueViolation :: ByteString -> SquealException
+ Squeal.PostgreSQL.Session.Exception: throwSqueal :: MonadUnliftIO io => SquealException -> io a
+ Squeal.PostgreSQL.Session.Exception: trySqueal :: MonadUnliftIO io => io a -> io (Either SquealException a)
+ Squeal.PostgreSQL.Session.Indexed: Indexed :: t i j m r -> Indexed t m r i j
+ Squeal.PostgreSQL.Session.Indexed: [runIndexed] :: Indexed t m r i j -> t i j m r
+ Squeal.PostgreSQL.Session.Indexed: class (forall i j m. Monad m => Functor (t i j m), forall i j m. (i ~ j, Monad m) => Monad (t i j m), forall i j. i ~ j => MonadTrans (t i j)) => IndexedMonadTrans t
+ Squeal.PostgreSQL.Session.Indexed: class IndexedMonadTrans pq => IndexedMonadTransPQ pq
+ Squeal.PostgreSQL.Session.Indexed: define :: (IndexedMonadTransPQ pq, MonadIO io) => Definition db0 db1 -> pq db0 db1 io ()
+ Squeal.PostgreSQL.Session.Indexed: indexedDefine :: (IndexedMonadTransPQ pq, MonadIO io) => Definition db0 db1 -> Indexed pq io () db0 db1
+ Squeal.PostgreSQL.Session.Indexed: instance forall k (t :: k -> k -> (* -> *) -> * -> *) (m :: * -> *) r. (Squeal.PostgreSQL.Session.Indexed.IndexedMonadTrans t, GHC.Base.Monad m, GHC.Base.Monoid r) => Control.Category.Category (Squeal.PostgreSQL.Session.Indexed.Indexed t m r)
+ Squeal.PostgreSQL.Session.Indexed: newtype Indexed t m r i j
+ Squeal.PostgreSQL.Session.Indexed: pqAndThen :: (IndexedMonadTrans t, Monad m) => (y -> t j k m z) -> (x -> t i j m y) -> x -> t i k m z
+ Squeal.PostgreSQL.Session.Indexed: pqAp :: (IndexedMonadTrans t, Monad m) => t i j m (x -> y) -> t j k m x -> t i k m y
+ Squeal.PostgreSQL.Session.Indexed: pqBind :: (IndexedMonadTrans t, Monad m) => (x -> t j k m y) -> t i j m x -> t i k m y
+ Squeal.PostgreSQL.Session.Indexed: pqJoin :: (IndexedMonadTrans t, Monad m) => t i j m (t j k m y) -> t i k m y
+ Squeal.PostgreSQL.Session.Indexed: pqThen :: (IndexedMonadTrans t, Monad m) => t j k m y -> t i j m x -> t i k m y
+ Squeal.PostgreSQL.Session.Migration: IsoQ :: c x y -> c y x -> IsoQ
+ Squeal.PostgreSQL.Session.Migration: Migration :: Text -> def db0 db1 -> Migration def db0 db1
+ Squeal.PostgreSQL.Session.Migration: [down] :: IsoQ -> c y x
+ Squeal.PostgreSQL.Session.Migration: [migration] :: Migration def db0 db1 -> def db0 db1
+ Squeal.PostgreSQL.Session.Migration: [name] :: Migration def db0 db1 -> Text
+ Squeal.PostgreSQL.Session.Migration: [up] :: IsoQ -> c x y
+ Squeal.PostgreSQL.Session.Migration: class (Category def, Category run) => Migratory def run | def -> run
+ Squeal.PostgreSQL.Session.Migration: data Migration def db0 db1
+ Squeal.PostgreSQL.Session.Migration: data IsoQ (c :: k -> k -> Type) (x :: k) (y :: k) :: forall k. () => k -> k -> Type -> k -> k -> Type
+ Squeal.PostgreSQL.Session.Migration: instance Data.Quiver.Functor.QFunctor Squeal.PostgreSQL.Session.Migration.Migration
+ Squeal.PostgreSQL.Session.Migration: instance GHC.Generics.Generic Squeal.PostgreSQL.Session.Migration.MigrationRow
+ Squeal.PostgreSQL.Session.Migration: instance GHC.Show.Show Squeal.PostgreSQL.Session.Migration.MigrationRow
+ Squeal.PostgreSQL.Session.Migration: instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Session.Migration.MigrationRow
+ Squeal.PostgreSQL.Session.Migration: instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Session.Migration.MigrationRow
+ Squeal.PostgreSQL.Session.Migration: instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.IsoQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) (Data.Quiver.IsoQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()))
+ Squeal.PostgreSQL.Session.Migration: instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.IsoQ Squeal.PostgreSQL.Definition.Definition) (Data.Quiver.IsoQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()))
+ Squeal.PostgreSQL.Session.Migration: instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.OpQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) (Data.Quiver.OpQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()))
+ Squeal.PostgreSQL.Session.Migration: instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.OpQ Squeal.PostgreSQL.Definition.Definition) (Data.Quiver.OpQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()))
+ Squeal.PostgreSQL.Session.Migration: instance Squeal.PostgreSQL.Session.Migration.Migratory (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()) (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())
+ Squeal.PostgreSQL.Session.Migration: instance Squeal.PostgreSQL.Session.Migration.Migratory Squeal.PostgreSQL.Definition.Definition (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())
+ Squeal.PostgreSQL.Session.Migration: instance forall k1 k2 (def :: k1 -> k2 -> *) (db0 :: k1) (db1 :: k2). GHC.Generics.Generic (Squeal.PostgreSQL.Session.Migration.Migration def db0 db1)
+ Squeal.PostgreSQL.Session.Migration: mainMigrate :: Migratory p (Indexed PQ IO ()) => ByteString -> Path (Migration p) db0 db1 -> IO ()
+ Squeal.PostgreSQL.Session.Migration: mainMigrateIso :: Migratory (IsoQ def) (IsoQ (Indexed PQ IO ())) => ByteString -> Path (Migration (IsoQ def)) db0 db1 -> IO ()
+ Squeal.PostgreSQL.Session.Migration: migrate :: Migratory def (Indexed PQ IO ()) => Path (Migration def) db0 db1 -> PQ db0 db1 IO ()
+ Squeal.PostgreSQL.Session.Migration: migrateDown :: Migratory def (IsoQ (Indexed PQ IO ())) => Path (Migration def) db0 db1 -> PQ db1 db0 IO ()
+ Squeal.PostgreSQL.Session.Migration: migrateUp :: Migratory def (IsoQ (Indexed PQ IO ())) => Path (Migration def) db0 db1 -> PQ db0 db1 IO ()
+ Squeal.PostgreSQL.Session.Migration: runMigrations :: Migratory def run => Path (Migration def) db0 db1 -> run db0 db1
+ Squeal.PostgreSQL.Session.Migration: type MigrationsTable = '["migrations_unique_name" ::: 'Unique '["name"]] :=> '["name" ::: 'NoDef :=> 'NotNull 'PGtext, "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz]
+ Squeal.PostgreSQL.Session.Monad: class Monad pq => MonadPQ db pq | pq -> db
+ Squeal.PostgreSQL.Session.Monad: execute :: MonadPQ db pq => Statement db () y -> pq (Result y)
+ Squeal.PostgreSQL.Session.Monad: executeParams :: (MonadPQ db pq, MonadTrans t, MonadPQ db m, pq ~ t m) => Statement db x y -> x -> pq (Result y)
+ Squeal.PostgreSQL.Session.Monad: executeParams_ :: MonadPQ db pq => Statement db x () -> x -> pq ()
+ Squeal.PostgreSQL.Session.Monad: executePrepared :: (MonadPQ db pq, MonadTrans t, MonadPQ db m, pq ~ t m) => Traversable list => Statement db x y -> list x -> pq (list (Result y))
+ Squeal.PostgreSQL.Session.Monad: executePrepared_ :: (MonadPQ db pq, MonadTrans t, MonadPQ db m, pq ~ t m) => Foldable list => Statement db x () -> list x -> pq ()
+ Squeal.PostgreSQL.Session.Monad: execute_ :: MonadPQ db pq => Statement db () () -> pq ()
+ Squeal.PostgreSQL.Session.Monad: forPrepared :: (MonadPQ db pq, GenericParams db params x xs, Traversable list, IsRecord y ys, AllZip FromField row ys) => list x -> Manipulation '[] db params row -> pq (list (Result y))
+ Squeal.PostgreSQL.Session.Monad: forPrepared_ :: (MonadPQ db pq, GenericParams db params x xs, Foldable list) => list x -> Manipulation '[] db params '[] -> pq ()
+ Squeal.PostgreSQL.Session.Monad: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.Session.Monad.MonadPQ db m) => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
+ Squeal.PostgreSQL.Session.Monad: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.Session.Monad.MonadPQ db m) => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.RWS.Strict.RWST r w s m)
+ Squeal.PostgreSQL.Session.Monad: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.Session.Monad.MonadPQ db m) => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Writer.Lazy.WriterT w m)
+ Squeal.PostgreSQL.Session.Monad: instance (GHC.Base.Monoid w, Squeal.PostgreSQL.Session.Monad.MonadPQ db m) => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Writer.Strict.WriterT w m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Cont.ContT r m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Except.ExceptT e m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Identity.IdentityT m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Maybe.MaybeT m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.Reader.ReaderT r m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.State.Lazy.StateT s m)
+ Squeal.PostgreSQL.Session.Monad: instance Squeal.PostgreSQL.Session.Monad.MonadPQ db m => Squeal.PostgreSQL.Session.Monad.MonadPQ db (Control.Monad.Trans.State.Strict.StateT s m)
+ Squeal.PostgreSQL.Session.Monad: manipulate :: (MonadPQ db pq, GenericRow row y ys) => Manipulation '[] db '[] row -> pq (Result y)
+ Squeal.PostgreSQL.Session.Monad: manipulateParams :: (MonadPQ db pq, GenericParams db params x xs, GenericRow row y ys) => Manipulation '[] db params row -> x -> pq (Result y)
+ Squeal.PostgreSQL.Session.Monad: manipulateParams_ :: (MonadPQ db pq, GenericParams db params x xs) => Manipulation '[] db params '[] -> x -> pq ()
+ Squeal.PostgreSQL.Session.Monad: manipulate_ :: MonadPQ db pq => Manipulation '[] db '[] '[] -> pq ()
+ Squeal.PostgreSQL.Session.Monad: runQuery :: (MonadPQ db pq, IsRecord y ys, AllZip FromField row ys) => Query '[] '[] db '[] row -> pq (Result y)
+ Squeal.PostgreSQL.Session.Monad: runQueryParams :: (MonadPQ db pq, GenericParams db params x xs, IsRecord y ys, AllZip FromField row ys) => Query '[] '[] db params row -> x -> pq (Result y)
+ Squeal.PostgreSQL.Session.Monad: traversePrepared :: (MonadPQ db pq, GenericParams db params x xs, Traversable list, IsRecord y ys, AllZip FromField row ys) => Manipulation '[] db params row -> list x -> pq (list (Result y))
+ Squeal.PostgreSQL.Session.Monad: traversePrepared_ :: (MonadPQ db pq, GenericParams db params x xs, Foldable list) => Manipulation '[] db params '[] -> list x -> pq ()
+ Squeal.PostgreSQL.Session.Oid: class OidOf (db :: SchemasType) (pg :: PGType)
+ Squeal.PostgreSQL.Session.Oid: class OidOfArray (db :: SchemasType) (pg :: PGType)
+ Squeal.PostgreSQL.Session.Oid: class OidOfField (db :: SchemasType) (field :: (Symbol, NullType))
+ Squeal.PostgreSQL.Session.Oid: class OidOfNull (db :: SchemasType) (ty :: NullType)
+ Squeal.PostgreSQL.Session.Oid: data Oid
+ Squeal.PostgreSQL.Session.Oid: instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGcomposite row))) => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row)
+ Squeal.PostgreSQL.Session.Oid: instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGcomposite row))) => Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row)
+ Squeal.PostgreSQL.Session.Oid: instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGenum labels)
+ Squeal.PostgreSQL.Session.Oid: instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) => Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGenum labels)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGbool
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGbytea
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGdate
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGfloat4
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGfloat8
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGinet
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGint2
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGint4
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGint8
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGjson
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGjsonb
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGmoney
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGnumeric
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGoid
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtext
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtime
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtimestamp
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtimetz
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtsquery
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtsvector
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGuuid
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGchar n)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGdate)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint4)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint8)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGnumeric)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamp)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGvarchar n)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOf db pg => Squeal.PostgreSQL.Session.Oid.OidOfNull db (null pg)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGbool
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGbytea
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGdate
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGfloat4
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGfloat8
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGinet
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGint2
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGint4
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGint8
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGinterval
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGjson
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGjsonb
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGmoney
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGnumeric
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGoid
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtext
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtime
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtimestamp
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtimetz
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtsquery
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtsvector
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGuuid
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGchar n)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGdate)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint4)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint8)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGnumeric)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamp)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGvarchar n)
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db pg => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGfixarray dims (null pg))
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfArray db pg => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGvararray (null pg))
+ Squeal.PostgreSQL.Session.Oid: instance Squeal.PostgreSQL.Session.Oid.OidOfNull db ty => Squeal.PostgreSQL.Session.Oid.OidOfField db (fld Squeal.PostgreSQL.Type.Alias.::: ty)
+ Squeal.PostgreSQL.Session.Oid: oidOf :: OidOf db pg => ReaderT (K Connection db) IO Oid
+ Squeal.PostgreSQL.Session.Oid: oidOfArray :: OidOfArray db pg => ReaderT (K Connection db) IO Oid
+ Squeal.PostgreSQL.Session.Oid: oidOfField :: OidOfField db field => ReaderT (K Connection db) IO Oid
+ Squeal.PostgreSQL.Session.Oid: oidOfNull :: OidOfNull db ty => ReaderT (K Connection db) IO Oid
+ Squeal.PostgreSQL.Session.Pool: createConnectionPool :: forall (db :: SchemasType) io. MonadUnliftIO io => ByteString -> Int -> NominalDiffTime -> Int -> io (Pool (K Connection db))
+ Squeal.PostgreSQL.Session.Pool: destroyConnectionPool :: MonadUnliftIO io => Pool (K Connection db) -> io ()
+ Squeal.PostgreSQL.Session.Pool: type Pool = Pool
+ Squeal.PostgreSQL.Session.Pool: usingConnectionPool :: MonadUnliftIO io => Pool (K Connection db) -> PQ db db io x -> io x
+ Squeal.PostgreSQL.Session.Result: [Result] :: SListI row => DecodeRow row y -> Result -> Result y
+ Squeal.PostgreSQL.Session.Result: data Result y
+ Squeal.PostgreSQL.Session.Result: firstRow :: MonadIO io => Result y -> io (Maybe y)
+ Squeal.PostgreSQL.Session.Result: getRow :: MonadIO io => Row -> Result y -> io y
+ Squeal.PostgreSQL.Session.Result: getRows :: MonadIO io => Result y -> io [y]
+ Squeal.PostgreSQL.Session.Result: instance GHC.Base.Functor Squeal.PostgreSQL.Session.Result.Result
+ Squeal.PostgreSQL.Session.Result: nextRow :: MonadIO io => Row -> Result y -> Row -> io (Maybe (Row, y))
+ Squeal.PostgreSQL.Session.Result: nfields :: MonadIO io => Result y -> io Column
+ Squeal.PostgreSQL.Session.Result: ntuples :: MonadIO io => Result y -> io Row
+ Squeal.PostgreSQL.Session.Result: okResult :: MonadIO io => K Result row -> io ()
+ Squeal.PostgreSQL.Session.Result: resultErrorCode :: MonadIO io => Result y -> io (Maybe ByteString)
+ Squeal.PostgreSQL.Session.Result: resultErrorMessage :: MonadIO io => Result y -> io (Maybe ByteString)
+ Squeal.PostgreSQL.Session.Result: resultStatus :: MonadIO io => Result y -> io ExecStatus
+ Squeal.PostgreSQL.Session.Statement: [Manipulation] :: (All (OidOfNull db) params, SListI row) => EncodeParams db params x -> DecodeRow row y -> Manipulation '[] db params row -> Statement db x y
+ Squeal.PostgreSQL.Session.Statement: [Query] :: (All (OidOfNull db) params, SListI row) => EncodeParams db params x -> DecodeRow row y -> Query '[] '[] db params row -> Statement db x y
+ Squeal.PostgreSQL.Session.Statement: data Statement db x y
+ Squeal.PostgreSQL.Session.Statement: instance Data.Profunctor.Unsafe.Profunctor (Squeal.PostgreSQL.Session.Statement.Statement db)
+ Squeal.PostgreSQL.Session.Statement: instance GHC.Base.Functor (Squeal.PostgreSQL.Session.Statement.Statement db x)
+ Squeal.PostgreSQL.Session.Statement: instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Session.Statement.Statement db x y)
+ Squeal.PostgreSQL.Session.Statement: manipulation :: (GenericParams db params x xs, GenericRow row y ys) => Manipulation '[] db params row -> Statement db x y
+ Squeal.PostgreSQL.Session.Statement: query :: (GenericParams db params x xs, GenericRow row y ys) => Query '[] '[] db params row -> Statement db x y
+ Squeal.PostgreSQL.Session.Statement: type GenericParams db params x xs = (All (OidOfNull db) params, IsProductType x xs, AllZip (ToParam db) params xs)
+ Squeal.PostgreSQL.Session.Statement: type GenericRow row y ys = (IsRecord y ys, AllZip FromField row ys)
+ Squeal.PostgreSQL.Session.Transaction: Deferrable :: DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: NotDeferrable :: DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: ReadCommitted :: IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: ReadOnly :: AccessMode
+ Squeal.PostgreSQL.Session.Transaction: ReadUncommitted :: IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: ReadWrite :: AccessMode
+ Squeal.PostgreSQL.Session.Transaction: RepeatableRead :: IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: Serializable :: IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: TransactionMode :: IsolationLevel -> AccessMode -> DeferrableMode -> TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: [accessMode] :: TransactionMode -> AccessMode
+ Squeal.PostgreSQL.Session.Transaction: [deferrableMode] :: TransactionMode -> DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: [isolationLevel] :: TransactionMode -> IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: begin :: TransactionMode -> Manipulation_ db () ()
+ Squeal.PostgreSQL.Session.Transaction: commit :: Manipulation_ db () ()
+ Squeal.PostgreSQL.Session.Transaction: data AccessMode
+ Squeal.PostgreSQL.Session.Transaction: data DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: data IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: data TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: defaultMode :: TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: ephemerally :: (MonadUnliftIO tx, MonadPQ db tx) => TransactionMode -> tx x -> tx x
+ Squeal.PostgreSQL.Session.Transaction: ephemerally_ :: (MonadUnliftIO tx, MonadPQ db tx) => tx x -> tx x
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Transaction.AccessMode
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Transaction.DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Transaction.IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Transaction.TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Session.Transaction.AccessMode
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Session.Transaction.DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Session.Transaction.IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: instance GHC.Show.Show Squeal.PostgreSQL.Session.Transaction.TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Session.Transaction.AccessMode
+ Squeal.PostgreSQL.Session.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Session.Transaction.DeferrableMode
+ Squeal.PostgreSQL.Session.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Session.Transaction.IsolationLevel
+ Squeal.PostgreSQL.Session.Transaction: instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Session.Transaction.TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: longRunningMode :: TransactionMode
+ Squeal.PostgreSQL.Session.Transaction: rollback :: Manipulation_ db () ()
+ Squeal.PostgreSQL.Session.Transaction: transactionally :: (MonadUnliftIO tx, MonadPQ db tx) => TransactionMode -> tx x -> tx x
+ Squeal.PostgreSQL.Session.Transaction: transactionallyRetry :: (MonadUnliftIO tx, MonadPQ db tx) => TransactionMode -> tx x -> tx x
+ Squeal.PostgreSQL.Session.Transaction: transactionally_ :: (MonadUnliftIO tx, MonadPQ db tx) => tx x -> tx x
+ Squeal.PostgreSQL.Type: Composite :: record -> Composite record
+ Squeal.PostgreSQL.Type: Enumerated :: enum -> Enumerated enum
+ Squeal.PostgreSQL.Type: FixArray :: arr -> FixArray arr
+ Squeal.PostgreSQL.Type: Json :: hask -> Json hask
+ Squeal.PostgreSQL.Type: Jsonb :: hask -> Jsonb hask
+ Squeal.PostgreSQL.Type: Money :: Int64 -> Money
+ Squeal.PostgreSQL.Type: Only :: x -> Only x
+ Squeal.PostgreSQL.Type: VarArray :: arr -> VarArray arr
+ Squeal.PostgreSQL.Type: [cents] :: Money -> Int64
+ Squeal.PostgreSQL.Type: [fromOnly] :: Only x -> x
+ Squeal.PostgreSQL.Type: [getComposite] :: Composite record -> record
+ Squeal.PostgreSQL.Type: [getEnumerated] :: Enumerated enum -> enum
+ Squeal.PostgreSQL.Type: [getFixArray] :: FixArray arr -> arr
+ Squeal.PostgreSQL.Type: [getJson] :: Json hask -> hask
+ Squeal.PostgreSQL.Type: [getJsonb] :: Jsonb hask -> hask
+ Squeal.PostgreSQL.Type: [getVarArray] :: VarArray arr -> arr
+ Squeal.PostgreSQL.Type: data FixChar (n :: Nat)
+ Squeal.PostgreSQL.Type: data VarChar (n :: Nat)
+ Squeal.PostgreSQL.Type: fixChar :: forall n. KnownNat n => Text -> Maybe (FixChar n)
+ Squeal.PostgreSQL.Type: getFixChar :: FixChar n -> Text
+ Squeal.PostgreSQL.Type: getVarChar :: VarChar n -> Text
+ Squeal.PostgreSQL.Type: instance Data.Foldable.Foldable Squeal.PostgreSQL.Type.Only
+ Squeal.PostgreSQL.Type: instance Data.Traversable.Traversable Squeal.PostgreSQL.Type.Only
+ Squeal.PostgreSQL.Type: instance GHC.Base.Functor Squeal.PostgreSQL.Type.Only
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.FixChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.VarChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq enum => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq record => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.FixChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.VarChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord enum => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord record => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Generics.Generic Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read (Squeal.PostgreSQL.Type.FixChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read (Squeal.PostgreSQL.Type.VarChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read enum => GHC.Read.Read (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read record => GHC.Read.Read (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show (Squeal.PostgreSQL.Type.FixChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show (Squeal.PostgreSQL.Type.VarChar n)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show enum => GHC.Show.Show (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show record => GHC.Show.Show (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Composite record)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Enumerated enum)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.FixArray arr)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Only x)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.VarArray arr)
+ Squeal.PostgreSQL.Type: instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type: newtype Composite record
+ Squeal.PostgreSQL.Type: newtype Enumerated enum
+ Squeal.PostgreSQL.Type: newtype FixArray arr
+ Squeal.PostgreSQL.Type: newtype Json hask
+ Squeal.PostgreSQL.Type: newtype Jsonb hask
+ Squeal.PostgreSQL.Type: newtype Money
+ Squeal.PostgreSQL.Type: newtype Only x
+ Squeal.PostgreSQL.Type: newtype VarArray arr
+ Squeal.PostgreSQL.Type: varChar :: forall n. KnownNat n => Text -> Maybe (VarChar n)
+ Squeal.PostgreSQL.Type.Alias: (!) :: IsQualified qualifier alias expression => Alias qualifier -> Alias alias -> expression
+ Squeal.PostgreSQL.Type.Alias: Alias :: Alias
+ Squeal.PostgreSQL.Type.Alias: Grouped :: [(Symbol, Symbol)] -> Grouping
+ Squeal.PostgreSQL.Type.Alias: QualifiedAlias :: QualifiedAlias
+ Squeal.PostgreSQL.Type.Alias: Ungrouped :: Grouping
+ Squeal.PostgreSQL.Type.Alias: [As] :: KnownSymbol alias => expression ty -> Alias alias -> Aliased expression (alias ::: ty)
+ Squeal.PostgreSQL.Type.Alias: as :: Aliasable alias expression aliased => expression -> Alias alias -> aliased
+ Squeal.PostgreSQL.Type.Alias: class KnownSymbol alias => Aliasable alias expression aliased | aliased -> expression, aliased -> alias
+ Squeal.PostgreSQL.Type.Alias: class (KnownSymbol table, KnownSymbol column) => GroupedBy table column bys
+ Squeal.PostgreSQL.Type.Alias: class KnownSymbol alias => Has (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) | alias fields -> field
+ Squeal.PostgreSQL.Type.Alias: class (All KnownSymbol aliases) => HasAll (aliases :: [Symbol]) (fields :: [(Symbol, kind)]) (subfields :: [(Symbol, kind)]) | aliases fields -> subfields
+ Squeal.PostgreSQL.Type.Alias: class HasIn fields field
+ Squeal.PostgreSQL.Type.Alias: class IsLabel (x :: Symbol) a
+ Squeal.PostgreSQL.Type.Alias: class IsQualified qualifier alias expression
+ Squeal.PostgreSQL.Type.Alias: data Alias (alias :: Symbol)
+ Squeal.PostgreSQL.Type.Alias: data Aliased expression aliased
+ Squeal.PostgreSQL.Type.Alias: data Grouping
+ Squeal.PostgreSQL.Type.Alias: data QualifiedAlias (qualifier :: Symbol) (alias :: Symbol)
+ Squeal.PostgreSQL.Type.Alias: fromLabel :: IsLabel x a => a
+ Squeal.PostgreSQL.Type.Alias: infixl 9 !
+ Squeal.PostgreSQL.Type.Alias: infixr 6 :::
+ Squeal.PostgreSQL.Type.Alias: instance (GHC.TypeLits.KnownSymbol q, GHC.TypeLits.KnownSymbol a) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q a)
+ Squeal.PostgreSQL.Type.Alias: instance (GHC.TypeLits.KnownSymbol table, GHC.TypeLits.KnownSymbol column) => Squeal.PostgreSQL.Type.Alias.GroupedBy table column ('(table, column) : bys)
+ Squeal.PostgreSQL.Type.Alias: instance (alias0 Data.Type.Equality.~ alias1, alias0 Data.Type.Equality.~ alias2, GHC.TypeLits.KnownSymbol alias2) => GHC.OverloadedLabels.IsLabel alias0 (Squeal.PostgreSQL.Type.Alias.Aliased Squeal.PostgreSQL.Type.Alias.Alias (alias1 Squeal.PostgreSQL.Type.Alias.::: alias2))
+ Squeal.PostgreSQL.Type.Alias: instance (alias1 Data.Type.Equality.~ alias2) => GHC.OverloadedLabels.IsLabel alias1 (Squeal.PostgreSQL.Type.Alias.Alias alias2)
+ Squeal.PostgreSQL.Type.Alias: instance (aliases Data.Type.Equality.~ '[alias]) => GHC.OverloadedLabels.IsLabel alias (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Alias.Alias aliases)
+ Squeal.PostgreSQL.Type.Alias: instance (q Data.Type.Equality.~ "public", a0 Data.Type.Equality.~ a1, a1 Data.Type.Equality.~ a2, GHC.TypeLits.KnownSymbol a2) => GHC.OverloadedLabels.IsLabel a0 (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q) (a1 Squeal.PostgreSQL.Type.Alias.::: a2))
+ Squeal.PostgreSQL.Type.Alias: instance (q Data.Type.Equality.~ q', a Data.Type.Equality.~ a') => Squeal.PostgreSQL.Type.Alias.IsQualified q a (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q' a')
+ Squeal.PostgreSQL.Type.Alias: instance (q' Data.Type.Equality.~ "public", a Data.Type.Equality.~ a') => GHC.OverloadedLabels.IsLabel a (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q' a')
+ Squeal.PostgreSQL.Type.Alias: instance (q0 Data.Type.Equality.~ q1, a0 Data.Type.Equality.~ a1, a1 Data.Type.Equality.~ a2, GHC.TypeLits.KnownSymbol a2) => Squeal.PostgreSQL.Type.Alias.IsQualified q0 a0 (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q1) (a1 Squeal.PostgreSQL.Type.Alias.::: a2))
+ Squeal.PostgreSQL.Type.Alias: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
+ Squeal.PostgreSQL.Type.Alias: instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol aliases => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Alias.Alias aliases)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Show.Show (Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.Show.Show (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
+ Squeal.PostgreSQL.Type.Alias: instance GHC.TypeLits.KnownSymbol alias => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance Squeal.PostgreSQL.Type.Alias.IsQualified qualifier alias (Squeal.PostgreSQL.Type.Alias.Alias qualifier, Squeal.PostgreSQL.Type.Alias.Alias alias)
+ Squeal.PostgreSQL.Type.Alias: instance forall a (table :: GHC.Types.Symbol) (column :: GHC.Types.Symbol) (bys :: [a]) (tabcol :: a). (GHC.TypeLits.KnownSymbol table, GHC.TypeLits.KnownSymbol column, Squeal.PostgreSQL.Type.Alias.GroupedBy table column bys) => Squeal.PostgreSQL.Type.Alias.GroupedBy table column (tabcol : bys)
+ Squeal.PostgreSQL.Type.Alias: instance forall k (alias :: GHC.Types.Symbol) (aliased :: (GHC.Types.Symbol, k)) (ty :: k) (expression :: k -> *). (GHC.TypeLits.KnownSymbol alias, aliased Data.Type.Equality.~ (alias Squeal.PostgreSQL.Type.Alias.::: ty)) => Squeal.PostgreSQL.Type.Alias.Aliasable alias (expression ty) (Squeal.PostgreSQL.Type.Alias.Aliased expression aliased)
+ Squeal.PostgreSQL.Type.Alias: instance forall k (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, k)]) (field :: k) (aliases :: [GHC.Types.Symbol]) (subfields :: [(GHC.Types.Symbol, k)]). (Squeal.PostgreSQL.Type.Alias.Has alias fields field, Squeal.PostgreSQL.Type.Alias.HasAll aliases fields subfields) => Squeal.PostgreSQL.Type.Alias.HasAll (alias : aliases) fields ((alias Squeal.PostgreSQL.Type.Alias.::: field) : subfields)
+ Squeal.PostgreSQL.Type.Alias: instance forall k (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, k)]) (field :: k). Squeal.PostgreSQL.Type.Alias.Has alias fields field => Squeal.PostgreSQL.Type.Alias.HasIn fields (alias Squeal.PostgreSQL.Type.Alias.::: field)
+ Squeal.PostgreSQL.Type.Alias: instance forall k (alias :: GHC.Types.Symbol) (tys :: [(GHC.Types.Symbol, k)]) (ty :: k) (expression :: k -> *). (GHC.TypeLits.KnownSymbol alias, tys Data.Type.Equality.~ '[alias Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.Aliasable alias (expression ty) (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased expression) tys)
+ Squeal.PostgreSQL.Type.Alias: instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Classes.Eq (expression ty) => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Alias.Aliased expression (alias Squeal.PostgreSQL.Type.Alias.::: ty))
+ Squeal.PostgreSQL.Type.Alias: instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Classes.Ord (expression ty) => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Alias.Aliased expression (alias Squeal.PostgreSQL.Type.Alias.::: ty))
+ Squeal.PostgreSQL.Type.Alias: instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Show.Show (expression ty) => GHC.Show.Show (Squeal.PostgreSQL.Type.Alias.Aliased expression (alias Squeal.PostgreSQL.Type.Alias.::: ty))
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (field0 :: kind) (field1 :: kind) (fields :: [(GHC.Types.Symbol, kind)]). (GHC.TypeLits.KnownSymbol alias, field0 Data.Type.Equality.~ field1) => Squeal.PostgreSQL.Type.Alias.Has alias ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) field1
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, kind)]) (field :: kind) (field' :: (GHC.Types.Symbol, kind)). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.Has alias fields field) => Squeal.PostgreSQL.Type.Alias.Has alias (field' : fields) field
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (fields :: [(GHC.Types.Symbol, kind)]). Squeal.PostgreSQL.Type.Alias.HasAll '[] fields '[]
+ Squeal.PostgreSQL.Type.Alias: mapAliased :: (expr x -> expr y) -> Aliased expr (alias ::: x) -> Aliased expr (alias ::: y)
+ Squeal.PostgreSQL.Type.Alias: renderAliased :: (forall ty. expression ty -> ByteString) -> Aliased expression aliased -> ByteString
+ Squeal.PostgreSQL.Type.Alias: type (:::) (alias :: Symbol) ty = '(alias, ty)
+ Squeal.PostgreSQL.Type.Alias: type HasUnique alias fields field = fields ~ '[alias ::: field]
+ Squeal.PostgreSQL.Type.List: (*:) :: f x -> f y -> NP f '[x, y]
+ Squeal.PostgreSQL.Type.List: [:*] :: forall k (a :: k -> Type) (b :: [k]) (x :: k) (xs :: [k]). () => a x -> NP a xs -> NP a (x : xs)
+ Squeal.PostgreSQL.Type.List: [:>>] :: forall k (p :: k -> k -> Type) (x :: k) (y :: k) (y1 :: k). () => p x y1 -> Path p y1 y -> Path p x y
+ Squeal.PostgreSQL.Type.List: [Done] :: forall k (p :: k -> k -> Type) (x :: k) (y :: k). () => Path p x x
+ Squeal.PostgreSQL.Type.List: [Nil] :: forall k (a :: k -> Type) (b :: [k]). () => NP a ([] :: [k])
+ Squeal.PostgreSQL.Type.List: also :: Additional expr => expr ys -> expr xs -> expr (Join xs ys)
+ Squeal.PostgreSQL.Type.List: class Additional expr
+ Squeal.PostgreSQL.Type.List: data Path (p :: k -> k -> Type) (x :: k) (y :: k) :: forall k. () => k -> k -> Type -> k -> k -> Type
+ Squeal.PostgreSQL.Type.List: disjoin :: forall xs ys expr. SListI xs => NP expr (Join xs ys) -> (NP expr xs, NP expr ys)
+ Squeal.PostgreSQL.Type.List: infixl 8 *:
+ Squeal.PostgreSQL.Type.List: infixr 5 :*
+ Squeal.PostgreSQL.Type.List: infixr 7 :>>
+ Squeal.PostgreSQL.Type.List: instance forall a (expr :: a -> *). Squeal.PostgreSQL.Type.List.Additional (Data.SOP.NP.NP expr)
+ Squeal.PostgreSQL.Type.List: one :: f x -> NP f '[x]
+ Squeal.PostgreSQL.Type.List: type family Length (xs :: [k]) :: Nat
+ Squeal.PostgreSQL.Type.PG: class IsPG (hask :: Type) where {
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Network.IP.Addr.NetAddr Network.IP.Addr.IP)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Composite hask)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Enumerated hask)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.FixArray hask)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.FixChar n)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Json hask)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Jsonb hask)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector x))
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.VarArray [x])
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.VarChar n)
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Aeson.Types.Internal.Value
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.ByteString.Internal.ByteString
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.ByteString.Lazy.Internal.ByteString
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Scientific.Scientific
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Text.Internal.Lazy.Text
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Text.Internal.Text
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.Calendar.Days.Day
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.Clock.Internal.DiffTime.DiffTime
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.Clock.Internal.UTCTime.UTCTime
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Data.UUID.Types.Internal.UUID
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Database.PostgreSQL.LibPQ.Oid
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Base.String
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Int.Int16
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Int.Int32
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Int.Int64
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Bool
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Char
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Double
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Float
+ Squeal.PostgreSQL.Type.PG: instance Squeal.PostgreSQL.Type.PG.IsPG Squeal.PostgreSQL.Type.Money
+ Squeal.PostgreSQL.Type.PG: type family ConstructorNamesOf (constructors :: [ConstructorInfo]) :: [ConstructorName]
+ Squeal.PostgreSQL.Type.PG: }
+ Squeal.PostgreSQL.Type.Schema: Brin :: IndexType
+ Squeal.PostgreSQL.Type.Schema: Btree :: IndexType
+ Squeal.PostgreSQL.Type.Schema: Check :: [Symbol] -> TableConstraint
+ Squeal.PostgreSQL.Type.Schema: Def :: Optionality
+ Squeal.PostgreSQL.Type.Schema: ForeignKey :: [Symbol] -> Symbol -> [Symbol] -> TableConstraint
+ Squeal.PostgreSQL.Type.Schema: Function :: FunctionType -> SchemumType
+ Squeal.PostgreSQL.Type.Schema: Gin :: IndexType
+ Squeal.PostgreSQL.Type.Schema: Gist :: IndexType
+ Squeal.PostgreSQL.Type.Schema: Hash :: IndexType
+ Squeal.PostgreSQL.Type.Schema: Index :: IndexType -> SchemumType
+ Squeal.PostgreSQL.Type.Schema: NoDef :: Optionality
+ Squeal.PostgreSQL.Type.Schema: NotNull :: PGType -> NullType
+ Squeal.PostgreSQL.Type.Schema: Null :: PGType -> NullType
+ Squeal.PostgreSQL.Type.Schema: PGbool :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGbytea :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGchar :: Nat -> PGType
+ Squeal.PostgreSQL.Type.Schema: PGcomposite :: RowType -> PGType
+ Squeal.PostgreSQL.Type.Schema: PGdate :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGenum :: [Symbol] -> PGType
+ Squeal.PostgreSQL.Type.Schema: PGfixarray :: [Nat] -> NullType -> PGType
+ Squeal.PostgreSQL.Type.Schema: PGfloat4 :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGfloat8 :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGinet :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGint2 :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGint4 :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGint8 :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGinterval :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGjson :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGjsonb :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGlabel :: PGlabel
+ Squeal.PostgreSQL.Type.Schema: PGmoney :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGnumeric :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGoid :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGrange :: PGType -> PGType
+ Squeal.PostgreSQL.Type.Schema: PGtext :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGtime :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGtimestamp :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGtimestamptz :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGtimetz :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGtsquery :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGtsvector :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGuuid :: PGType
+ Squeal.PostgreSQL.Type.Schema: PGvararray :: NullType -> PGType
+ Squeal.PostgreSQL.Type.Schema: PGvarchar :: Nat -> PGType
+ Squeal.PostgreSQL.Type.Schema: PrimaryKey :: [Symbol] -> TableConstraint
+ Squeal.PostgreSQL.Type.Schema: Returns :: NullType -> ReturnsType
+ Squeal.PostgreSQL.Type.Schema: ReturnsTable :: RowType -> ReturnsType
+ Squeal.PostgreSQL.Type.Schema: Spgist :: IndexType
+ Squeal.PostgreSQL.Type.Schema: Table :: TableType -> SchemumType
+ Squeal.PostgreSQL.Type.Schema: Typedef :: PGType -> SchemumType
+ Squeal.PostgreSQL.Type.Schema: Unique :: [Symbol] -> TableConstraint
+ Squeal.PostgreSQL.Type.Schema: UnsafePGType :: Symbol -> PGType
+ Squeal.PostgreSQL.Type.Schema: UnsafeSchemum :: Symbol -> SchemumType
+ Squeal.PostgreSQL.Type.Schema: View :: RowType -> SchemumType
+ Squeal.PostgreSQL.Type.Schema: class AllUnique (xs :: [(Symbol, a)])
+ Squeal.PostgreSQL.Type.Schema: class IsNotElem x isElem
+ Squeal.PostgreSQL.Type.Schema: class IsPGlabel (label :: Symbol) expr
+ Squeal.PostgreSQL.Type.Schema: class SamePGType (ty0 :: (Symbol, ColumnType)) (ty1 :: (Symbol, ColumnType))
+ Squeal.PostgreSQL.Type.Schema: data IndexType
+ Squeal.PostgreSQL.Type.Schema: data NullType
+ Squeal.PostgreSQL.Type.Schema: data Optionality
+ Squeal.PostgreSQL.Type.Schema: data PGType
+ Squeal.PostgreSQL.Type.Schema: data PGlabel (label :: Symbol)
+ Squeal.PostgreSQL.Type.Schema: data ReturnsType
+ Squeal.PostgreSQL.Type.Schema: data SchemumType
+ Squeal.PostgreSQL.Type.Schema: data TableConstraint
+ Squeal.PostgreSQL.Type.Schema: infixr 7 :=>
+ Squeal.PostgreSQL.Type.Schema: instance (label Data.Type.Equality.~ label1) => Squeal.PostgreSQL.Type.Schema.IsPGlabel label (Squeal.PostgreSQL.Type.Schema.PGlabel label1)
+ Squeal.PostgreSQL.Type.Schema: instance (labels Data.Type.Equality.~ '[label]) => Squeal.PostgreSQL.Type.Schema.IsPGlabel label (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Schema.PGlabel labels)
+ Squeal.PostgreSQL.Type.Schema: instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol labels => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Schema.PGlabel labels)
+ Squeal.PostgreSQL.Type.Schema: instance GHC.TypeLits.KnownSymbol label => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Type.Schema.PGlabel label)
+ Squeal.PostgreSQL.Type.Schema: instance Squeal.PostgreSQL.Type.Schema.AllUnique '[]
+ Squeal.PostgreSQL.Type.Schema: instance forall a (x :: (GHC.Types.Symbol, a)) (xs :: [(GHC.Types.Symbol, a)]). (Squeal.PostgreSQL.Type.Schema.IsNotElem x (Squeal.PostgreSQL.Type.List.Elem x xs), Squeal.PostgreSQL.Type.Schema.AllUnique xs) => Squeal.PostgreSQL.Type.Schema.AllUnique (x : xs)
+ Squeal.PostgreSQL.Type.Schema: instance forall k (ty0 :: k) (ty1 :: k) (alias0 :: GHC.Types.Symbol) (def0 :: Squeal.PostgreSQL.Type.Schema.Optionality) (null0 :: k -> Squeal.PostgreSQL.Type.Schema.NullType) (alias1 :: GHC.Types.Symbol) (def1 :: Squeal.PostgreSQL.Type.Schema.Optionality) (null1 :: k -> Squeal.PostgreSQL.Type.Schema.NullType). (ty0 Data.Type.Equality.~ ty1) => Squeal.PostgreSQL.Type.Schema.SamePGType (alias0 Squeal.PostgreSQL.Type.Alias.::: (def0 Squeal.PostgreSQL.Type.Schema.:=> null0 ty0)) (alias1 Squeal.PostgreSQL.Type.Alias.::: (def1 Squeal.PostgreSQL.Type.Schema.:=> null1 ty1))
+ Squeal.PostgreSQL.Type.Schema: instance forall k (x :: k). Squeal.PostgreSQL.Type.Schema.IsNotElem x 'GHC.Types.False
+ Squeal.PostgreSQL.Type.Schema: instance forall k1 k2 (alias :: k2) (a :: k1). (TypeError ...) => Squeal.PostgreSQL.Type.Schema.IsNotElem '(alias, a) 'GHC.Types.True
+ Squeal.PostgreSQL.Type.Schema: label :: IsPGlabel label expr => expr
+ Squeal.PostgreSQL.Type.Schema: type (:=>) constraint ty = '(constraint, ty)
+ Squeal.PostgreSQL.Type.Schema: type ColumnType = (Optionality, NullType)
+ Squeal.PostgreSQL.Type.Schema: type ColumnsType = [(Symbol, ColumnType)]
+ Squeal.PostgreSQL.Type.Schema: type FromType = [(Symbol, RowType)]
+ Squeal.PostgreSQL.Type.Schema: type FunctionType = ([NullType], ReturnsType)
+ Squeal.PostgreSQL.Type.Schema: type PGFloating = '[ 'PGfloat4, 'PGfloat8, 'PGnumeric]
+ Squeal.PostgreSQL.Type.Schema: type PGIntegral = '[ 'PGint2, 'PGint4, 'PGint8]
+ Squeal.PostgreSQL.Type.Schema: type PGJsonKey = '[ 'PGint2, 'PGint4, 'PGtext]
+ Squeal.PostgreSQL.Type.Schema: type PGJsonType = '[ 'PGjson, 'PGjsonb]
+ Squeal.PostgreSQL.Type.Schema: type PGNum = '[ 'PGint2, 'PGint4, 'PGint8, 'PGnumeric, 'PGfloat4, 'PGfloat8]
+ Squeal.PostgreSQL.Type.Schema: type RowType = [(Symbol, NullType)]
+ Squeal.PostgreSQL.Type.Schema: type SchemaType = [(Symbol, SchemumType)]
+ Squeal.PostgreSQL.Type.Schema: type SchemasType = [(Symbol, SchemaType)]
+ Squeal.PostgreSQL.Type.Schema: type TableConstraints = [(Symbol, TableConstraint)]
+ Squeal.PostgreSQL.Type.Schema: type TableType = (TableConstraints, ColumnsType)
+ Squeal.PostgreSQL.Type.Schema: type Updatable table columns = (All (HasIn (TableToColumns table)) columns, AllUnique columns, SListI (TableToColumns table))
+ Squeal.PostgreSQL.Type.Schema: type family UserTypeNamespace (sch :: Symbol) (td :: Maybe Symbol) (schemas :: SchemasType) (ty :: PGType)
- Squeal.PostgreSQL.Definition: newtype Definition (schemas0 :: SchemasType) (schemas1 :: SchemasType)
+ Squeal.PostgreSQL.Definition: newtype Definition (db0 :: SchemasType) (db1 :: SchemasType)
- Squeal.PostgreSQL.Expression: (<@) :: PGSubset container => Operator (null0 container) (null1 container) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression: (<@) :: PGSubset ty => Operator (null0 ty) (null1 ty) ( 'Null 'PGbool)
- Squeal.PostgreSQL.Expression: (@>) :: PGSubset container => Operator (null0 container) (null1 container) ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression: (@>) :: PGSubset ty => Operator (null0 ty) (null1 ty) ( 'Null 'PGbool)
- Squeal.PostgreSQL.Expression: class PGSubset container
+ Squeal.PostgreSQL.Expression: class PGSubset ty
- Squeal.PostgreSQL.Expression: newtype Expression (outer :: FromType) (commons :: FromType) (grp :: Grouping) (schemas :: SchemasType) (params :: [NullityType]) (from :: FromType) (ty :: NullityType)
+ Squeal.PostgreSQL.Expression: newtype Expression (grp :: Grouping) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType) (ty :: NullType)
- Squeal.PostgreSQL.Expression: type (:-->) x y = forall outer commons grp schemas params from. Expression outer commons grp schemas params from x " input" -> Expression outer commons grp schemas params from y " output"
+ Squeal.PostgreSQL.Expression: type (--->) xs y = forall db. FunN db xs y
- Squeal.PostgreSQL.Expression: type Expr x = forall outer commons grp schemas params from. Expression outer commons grp schemas params from x " cannot reference aliases"
+ Squeal.PostgreSQL.Expression: type Expr x = forall grp lat with db params from. Expression grp lat with db params from x " cannot reference aliases"
- Squeal.PostgreSQL.Expression: type FunctionVar x0 x1 y = forall outer commons grp schemas params from. [Expression outer commons grp schemas params from x0] " inputs" -> Expression outer commons grp schemas params from x1 " must have at least 1 input" -> Expression outer commons grp schemas params from y " output"
+ Squeal.PostgreSQL.Expression: type FunctionVar x0 x1 y = forall grp lat with db params from. [Expression grp lat with db params from x0] " inputs" -> Expression grp lat with db params from x1 " must have at least 1 input" -> Expression grp lat with db params from y " output"
- Squeal.PostgreSQL.Expression: type Operator x1 x2 y = forall outer commons grp schemas params from. Expression outer commons grp schemas params from x1 " left input" -> Expression outer commons grp schemas params from x2 " right input" -> Expression outer commons grp schemas params from y " output"
+ Squeal.PostgreSQL.Expression: type Operator x1 x2 y = forall grp lat with db params from. Expression grp lat with db params from x1 " left input" -> Expression grp lat with db params from x2 " right input" -> Expression grp lat with db params from y " output"
- Squeal.PostgreSQL.Expression: unsafeFunction :: ByteString -> x :--> y
+ Squeal.PostgreSQL.Expression: unsafeFunction :: ByteString -> x --> y
- Squeal.PostgreSQL.Expression: unsafeFunctionN :: SListI xs => ByteString -> FunctionN xs y
+ Squeal.PostgreSQL.Expression: unsafeFunctionN :: SListI xs => ByteString -> xs ---> y
- Squeal.PostgreSQL.Expression.Aggregate: arrayAgg :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'Null ( 'PGvararray ty))
+ Squeal.PostgreSQL.Expression.Aggregate: arrayAgg :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'Null ( 'PGvararray ty))
- Squeal.PostgreSQL.Expression.Aggregate: avg :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: avg :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Aggregate: bitAnd :: (Aggregate expr1 exprN aggr, int `In` PGIntegral) => expr1 (null int) -> aggr ( 'Null int)
+ Squeal.PostgreSQL.Expression.Aggregate: bitAnd :: (Aggregate arg expr, int `In` PGIntegral) => arg '[null int] lat with db params from -> expr lat with db params from ( 'Null int)
- Squeal.PostgreSQL.Expression.Aggregate: bitOr :: (Aggregate expr1 exprN aggr, int `In` PGIntegral) => expr1 (null int) -> aggr ( 'Null int)
+ Squeal.PostgreSQL.Expression.Aggregate: bitOr :: (Aggregate arg expr, int `In` PGIntegral) => arg '[null int] lat with db params from -> expr lat with db params from ( 'Null int)
- Squeal.PostgreSQL.Expression.Aggregate: boolAnd :: Aggregate expr1 exprN aggr => expr1 (null 'PGbool) -> aggr ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Aggregate: boolAnd :: Aggregate arg expr => arg '[null 'PGbool] lat with db params from -> expr lat with db params from ( 'Null 'PGbool)
- Squeal.PostgreSQL.Expression.Aggregate: boolOr :: Aggregate expr1 exprN aggr => expr1 (null 'PGbool) -> aggr ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Aggregate: boolOr :: Aggregate arg expr => arg '[null 'PGbool] lat with db params from -> expr lat with db params from ( 'Null 'PGbool)
- Squeal.PostgreSQL.Expression.Aggregate: class Aggregate expr1 exprN aggr | aggr -> expr1, aggr -> exprN
+ Squeal.PostgreSQL.Expression.Aggregate: class Aggregate arg expr | expr -> arg
- Squeal.PostgreSQL.Expression.Aggregate: corr :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: corr :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: count :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'NotNull 'PGint8)
+ Squeal.PostgreSQL.Expression.Aggregate: count :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'NotNull 'PGint8)
- Squeal.PostgreSQL.Expression.Aggregate: countStar :: Aggregate expr1 exprN aggr => aggr ( 'NotNull 'PGint8)
+ Squeal.PostgreSQL.Expression.Aggregate: countStar :: Aggregate arg expr => expr lat with db params from ( 'NotNull 'PGint8)
- Squeal.PostgreSQL.Expression.Aggregate: covarPop :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: covarPop :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: covarSamp :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: covarSamp :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: every :: Aggregate expr1 exprN aggr => expr1 (null 'PGbool) -> aggr ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Aggregate: every :: Aggregate arg expr => arg '[null 'PGbool] lat with db params from -> expr lat with db params from ( 'Null 'PGbool)
- Squeal.PostgreSQL.Expression.Aggregate: jsonAgg :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'Null 'PGjson)
+ Squeal.PostgreSQL.Expression.Aggregate: jsonAgg :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'Null 'PGjson)
- Squeal.PostgreSQL.Expression.Aggregate: jsonbAgg :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'Null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Aggregate: jsonbAgg :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'Null 'PGjsonb)
- Squeal.PostgreSQL.Expression.Aggregate: max_ :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null ty)
+ Squeal.PostgreSQL.Expression.Aggregate: max_ :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null ty)
- Squeal.PostgreSQL.Expression.Aggregate: min_ :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null ty)
+ Squeal.PostgreSQL.Expression.Aggregate: min_ :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null ty)
- Squeal.PostgreSQL.Expression.Aggregate: regrAvgX :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrAvgX :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrAvgY :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrAvgY :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrCount :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGint8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrCount :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGint8)
- Squeal.PostgreSQL.Expression.Aggregate: regrIntercept :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrIntercept :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrR2 :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrR2 :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrSlope :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrSlope :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrSxx :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrSxx :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrSxy :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrSxy :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: regrSyy :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Aggregate: regrSyy :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Aggregate: stddev :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: stddev :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Aggregate: stddevPop :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: stddevPop :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Aggregate: stddevSamp :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: stddevSamp :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Aggregate: sum_ :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGSum ty))
+ Squeal.PostgreSQL.Expression.Aggregate: sum_ :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGSum ty))
- Squeal.PostgreSQL.Expression.Aggregate: varPop :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: varPop :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Aggregate: varSamp :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: varSamp :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Aggregate: variance :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
+ Squeal.PostgreSQL.Expression.Aggregate: variance :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
- Squeal.PostgreSQL.Expression.Comparison: isFalse :: null0 'PGbool :--> null1 'PGbool
+ Squeal.PostgreSQL.Expression.Comparison: isFalse :: null0 'PGbool --> null1 'PGbool
- Squeal.PostgreSQL.Expression.Comparison: isNotFalse :: null0 'PGbool :--> null1 'PGbool
+ Squeal.PostgreSQL.Expression.Comparison: isNotFalse :: null0 'PGbool --> null1 'PGbool
- Squeal.PostgreSQL.Expression.Comparison: isNotTrue :: null0 'PGbool :--> null1 'PGbool
+ Squeal.PostgreSQL.Expression.Comparison: isNotTrue :: null0 'PGbool --> null1 'PGbool
- Squeal.PostgreSQL.Expression.Comparison: isNotUnknown :: null0 'PGbool :--> null1 'PGbool
+ Squeal.PostgreSQL.Expression.Comparison: isNotUnknown :: null0 'PGbool --> null1 'PGbool
- Squeal.PostgreSQL.Expression.Comparison: isTrue :: null0 'PGbool :--> null1 'PGbool
+ Squeal.PostgreSQL.Expression.Comparison: isTrue :: null0 'PGbool --> null1 'PGbool
- Squeal.PostgreSQL.Expression.Comparison: isUnknown :: null0 'PGbool :--> null1 'PGbool
+ Squeal.PostgreSQL.Expression.Comparison: isUnknown :: null0 'PGbool --> null1 'PGbool
- Squeal.PostgreSQL.Expression.Comparison: type BetweenExpr = forall outer commons grp schemas params from ty. Expression outer commons grp schemas params from ty -> (Expression outer commons grp schemas params from ty, Expression outer commons grp schemas params from ty) " bounds" -> Condition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Comparison: type BetweenExpr = forall grp lat with db params from ty. Expression grp lat with db params from ty -> (Expression grp lat with db params from ty, Expression grp lat with db params from ty) " bounds" -> Condition grp lat with db params from
- Squeal.PostgreSQL.Expression.Json: arrayToJson :: null ( 'PGvararray ty) :--> null 'PGjson
+ Squeal.PostgreSQL.Expression.Json: arrayToJson :: null ( 'PGvararray ty) --> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: jsonArrayLength :: null 'PGjson :--> null 'PGint4
+ Squeal.PostgreSQL.Expression.Json: jsonArrayLength :: null 'PGjson --> null 'PGint4
- Squeal.PostgreSQL.Expression.Json: jsonBuildArray :: SListI tuple => FunctionN tuple (null 'PGjson)
+ Squeal.PostgreSQL.Expression.Json: jsonBuildArray :: SListI tuple => tuple ---> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: jsonBuildObject :: JsonBuildObject tys => FunctionN tys (null 'PGjson)
+ Squeal.PostgreSQL.Expression.Json: jsonBuildObject :: JsonBuildObject tys => tys ---> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: jsonEach :: SetOfFunction "json_each" (null 'PGjson) '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
+ Squeal.PostgreSQL.Expression.Json: jsonEach :: null 'PGjson -|-> ("json_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson])
- Squeal.PostgreSQL.Expression.Json: jsonEachText :: SetOfFunction "json_each_text" (null 'PGjson) '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
+ Squeal.PostgreSQL.Expression.Json: jsonEachText :: null 'PGjson -|-> ("json_each_text" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext])
- Squeal.PostgreSQL.Expression.Json: jsonObject :: null ( 'PGfixarray '[n, 2] ( 'NotNull 'PGtext)) :--> null 'PGjson
+ Squeal.PostgreSQL.Expression.Json: jsonObject :: null ( 'PGfixarray '[n, 2] ( 'NotNull 'PGtext)) --> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: jsonObjectKeys :: SetOfFunction "json_object_keys" (nullity 'PGjson) '["json_object_keys" ::: 'NotNull 'PGtext]
+ Squeal.PostgreSQL.Expression.Json: jsonObjectKeys :: null 'PGjson -|-> ("json_object_keys" ::: '["json_object_keys" ::: 'NotNull 'PGtext])
- Squeal.PostgreSQL.Expression.Json: jsonStripNulls :: null 'PGjson :--> null 'PGjson
+ Squeal.PostgreSQL.Expression.Json: jsonStripNulls :: null 'PGjson --> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: jsonTypeof :: null 'PGjson :--> null 'PGtext
+ Squeal.PostgreSQL.Expression.Json: jsonTypeof :: null 'PGjson --> null 'PGtext
- Squeal.PostgreSQL.Expression.Json: jsonZipObject :: FunctionN '[null ( 'PGvararray ( 'NotNull 'PGtext)), null ( 'PGvararray ( 'NotNull 'PGtext))] (null 'PGjson)
+ Squeal.PostgreSQL.Expression.Json: jsonZipObject :: '[null ( 'PGvararray ( 'NotNull 'PGtext)), null ( 'PGvararray ( 'NotNull 'PGtext))] ---> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
+ Squeal.PostgreSQL.Expression.Json: jsonbArrayLength :: null 'PGjsonb --> null 'PGint4
- Squeal.PostgreSQL.Expression.Json: jsonbBuildArray :: SListI tuple => FunctionN tuple (null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Json: jsonbBuildArray :: SListI tuple => tuple ---> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: jsonbBuildObject :: JsonBuildObject tys => FunctionN tys (null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Json: jsonbBuildObject :: JsonBuildObject tys => tys ---> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: jsonbEach :: SetOfFunction "jsonb_each" (nullity 'PGjsonb) '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
+ Squeal.PostgreSQL.Expression.Json: jsonbEach :: null 'PGjsonb -|-> ("jsonb_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson])
- Squeal.PostgreSQL.Expression.Json: jsonbEachText :: SetOfFunction "jsonb_each_text" (null 'PGjsonb) '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
+ Squeal.PostgreSQL.Expression.Json: jsonbEachText :: null 'PGjsonb -|-> ("jsonb_each_text" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext])
- Squeal.PostgreSQL.Expression.Json: jsonbInsert :: FunctionN '[null 'PGjsonb, null ( 'PGvararray ( 'NotNull 'PGtext)), null 'PGjsonb, null 'PGbool] (null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Json: jsonbInsert :: '[null 'PGjsonb, null ( 'PGvararray ( 'NotNull 'PGtext)), null 'PGjsonb, null 'PGbool] ---> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: jsonbObject :: null ( 'PGfixarray '[n, 2] ( 'NotNull 'PGtext)) :--> null 'PGjsonb
+ Squeal.PostgreSQL.Expression.Json: jsonbObject :: null ( 'PGfixarray '[n, 2] ( 'NotNull 'PGtext)) --> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: jsonbObjectKeys :: SetOfFunction "jsonb_object_keys" (null 'PGjsonb) '["jsonb_object_keys" ::: 'NotNull 'PGtext]
+ Squeal.PostgreSQL.Expression.Json: jsonbObjectKeys :: null 'PGjsonb -|-> ("jsonb_object_keys" ::: '["jsonb_object_keys" ::: 'NotNull 'PGtext])
- Squeal.PostgreSQL.Expression.Json: jsonbPretty :: null 'PGjsonb :--> null 'PGtext
+ Squeal.PostgreSQL.Expression.Json: jsonbPretty :: null 'PGjsonb --> null 'PGtext
- Squeal.PostgreSQL.Expression.Json: jsonbSet :: FunctionN '[null 'PGjsonb, null ( 'PGvararray ( 'NotNull 'PGtext)), null 'PGjsonb, null 'PGbool] (null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Json: jsonbSet :: '[null 'PGjsonb, null ( 'PGvararray ( 'NotNull 'PGtext)), null 'PGjsonb, null 'PGbool] ---> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
+ Squeal.PostgreSQL.Expression.Json: jsonbStripNulls :: null 'PGjsonb --> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: jsonbTypeof :: null 'PGjsonb :--> null 'PGtext
+ Squeal.PostgreSQL.Expression.Json: jsonbTypeof :: null 'PGjsonb --> null 'PGtext
- Squeal.PostgreSQL.Expression.Json: jsonbZipObject :: FunctionN '[null ( 'PGvararray ( 'NotNull 'PGtext)), null ( 'PGvararray ( 'NotNull 'PGtext))] (null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Json: jsonbZipObject :: '[null ( 'PGvararray ( 'NotNull 'PGtext)), null ( 'PGvararray ( 'NotNull 'PGtext))] ---> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: rowToJson :: null ( 'PGcomposite ty) :--> null 'PGjson
+ Squeal.PostgreSQL.Expression.Json: rowToJson :: null ( 'PGcomposite ty) --> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: toJson :: null ty :--> null 'PGjson
+ Squeal.PostgreSQL.Expression.Json: toJson :: null ty --> null 'PGjson
- Squeal.PostgreSQL.Expression.Json: toJsonb :: null ty :--> null 'PGjsonb
+ Squeal.PostgreSQL.Expression.Json: toJsonb :: null ty --> null 'PGjsonb
- Squeal.PostgreSQL.Expression.Json: type JsonToRecordFunction json = forall outer commons schemas params tab row. (SListI row, json `In` PGJsonType) => Expression outer commons 'Ungrouped schemas params '[] ( 'NotNull json) " json type" -> Aliased (NP (Aliased (TypeExpression schemas))) (tab ::: row) " row type" -> FromClause outer commons schemas params '[tab ::: row]
+ Squeal.PostgreSQL.Expression.Json: type JsonToRecordFunction json = forall lat with db params tab row. (SListI row, json `In` PGJsonType) => Expression 'Ungrouped lat with db params '[] ( 'NotNull json) " json type" -> Aliased (NP (Aliased (TypeExpression db))) (tab ::: row) " row type" -> FromClause lat with db params '[tab ::: row]
- Squeal.PostgreSQL.Expression.Json: type JsonPopulateFunction fun json = forall schemas row outer commons params. json `In` PGJsonType => TypeExpression schemas ( 'NotNull ( 'PGcomposite row)) " row type" -> Expression outer commons 'Ungrouped schemas params '[] ( 'NotNull json) " json type" -> FromClause outer commons schemas params '[fun ::: row]
+ Squeal.PostgreSQL.Expression.Json: type JsonPopulateFunction fun json = forall db row lat with params. json `In` PGJsonType => TypeExpression db ( 'NotNull ( 'PGcomposite row)) " row type" -> Expression 'Ungrouped lat with db params '[] ( 'NotNull json) " json type" -> FromClause lat with db params '[fun ::: row]
- Squeal.PostgreSQL.Expression.Logic: caseWhenThenElse :: [(Condition outer commons grp schemas params from, Expression outer commons grp schemas params from ty)] -> Expression outer commons grp schemas params from ty -> Expression outer commons grp schemas params from ty
+ Squeal.PostgreSQL.Expression.Logic: caseWhenThenElse :: [(Condition grp lat with db params from, Expression grp lat with db params from ty)] -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty
- Squeal.PostgreSQL.Expression.Logic: ifThenElse :: Condition outer commons grp schemas params from -> Expression outer commons grp schemas params from ty -> Expression outer commons grp schemas params from ty -> Expression outer commons grp schemas params from ty
+ Squeal.PostgreSQL.Expression.Logic: ifThenElse :: Condition grp lat with db params from -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty
- Squeal.PostgreSQL.Expression.Logic: not_ :: null 'PGbool :--> null 'PGbool
+ Squeal.PostgreSQL.Expression.Logic: not_ :: null 'PGbool --> null 'PGbool
- Squeal.PostgreSQL.Expression.Logic: type Condition outer commons grp schemas params from = Expression outer commons grp schemas params from ( 'Null 'PGbool)
+ Squeal.PostgreSQL.Expression.Logic: type Condition grp lat with db params from = Expression grp lat with db params from ( 'Null 'PGbool)
- Squeal.PostgreSQL.Expression.Math: atan2_ :: float `In` PGFloating => FunctionN '[null float, null float] (null float)
+ Squeal.PostgreSQL.Expression.Math: atan2_ :: float `In` PGFloating => '[null float, null float] ---> null float
- Squeal.PostgreSQL.Expression.Math: ceiling_ :: frac `In` PGFloating => null frac :--> null frac
+ Squeal.PostgreSQL.Expression.Math: ceiling_ :: frac `In` PGFloating => null frac --> null frac
- Squeal.PostgreSQL.Expression.Math: round_ :: frac `In` PGFloating => null frac :--> null frac
+ Squeal.PostgreSQL.Expression.Math: round_ :: frac `In` PGFloating => null frac --> null frac
- Squeal.PostgreSQL.Expression.Math: trunc :: frac `In` PGFloating => null frac :--> null frac
+ Squeal.PostgreSQL.Expression.Math: trunc :: frac `In` PGFloating => null frac --> null frac
- Squeal.PostgreSQL.Expression.Null: coalesce :: FunctionVar ( 'Null ty) ( 'NotNull ty) ( 'NotNull ty)
+ Squeal.PostgreSQL.Expression.Null: coalesce :: FunctionVar ( 'Null ty) (null ty) (null ty)
- Squeal.PostgreSQL.Expression.Null: fromNull :: Expression outer commons grp schemas params from ( 'NotNull ty) -> Expression outer commons grp schemas params from ( 'Null ty) -> Expression outer commons grp schemas params from ( 'NotNull ty)
+ Squeal.PostgreSQL.Expression.Null: fromNull :: Expression grp lat with db params from ( 'NotNull ty) -> Expression grp lat with db params from ( 'Null ty) -> Expression grp lat with db params from ( 'NotNull ty)
- Squeal.PostgreSQL.Expression.Null: isNotNull :: 'Null ty :--> null 'PGbool
+ Squeal.PostgreSQL.Expression.Null: isNotNull :: 'Null ty --> null 'PGbool
- Squeal.PostgreSQL.Expression.Null: isNull :: 'Null ty :--> null 'PGbool
+ Squeal.PostgreSQL.Expression.Null: isNull :: 'Null ty --> null 'PGbool
- Squeal.PostgreSQL.Expression.Null: matchNull :: Expression outer commons grp schemas params from nullty -> (Expression outer commons grp schemas params from ( 'NotNull ty) -> Expression outer commons grp schemas params from nullty) -> Expression outer commons grp schemas params from ( 'Null ty) -> Expression outer commons grp schemas params from nullty
+ Squeal.PostgreSQL.Expression.Null: matchNull :: Expression grp lat with db params from nullty -> (Expression grp lat with db params from ( 'NotNull ty) -> Expression grp lat with db params from nullty) -> Expression grp lat with db params from ( 'Null ty) -> Expression grp lat with db params from nullty
- Squeal.PostgreSQL.Expression.Null: notNull :: 'NotNull ty :--> 'Null ty
+ Squeal.PostgreSQL.Expression.Null: notNull :: 'NotNull ty --> 'Null ty
- Squeal.PostgreSQL.Expression.Null: nullIf :: FunctionN '[ 'NotNull ty, 'NotNull ty] ( 'Null ty)
+ Squeal.PostgreSQL.Expression.Null: nullIf :: '[ 'NotNull ty, 'NotNull ty] ---> 'Null ty
- Squeal.PostgreSQL.Expression.Parameter: class KnownNat n => HasParameter (n :: Nat) (params :: [NullityType]) (ty :: NullityType) | n params -> ty
+ Squeal.PostgreSQL.Expression.Parameter: class KnownNat n => HasParameter (n :: Nat) (params :: [NullType]) (ty :: NullType) | n params -> ty
- Squeal.PostgreSQL.Expression.Parameter: param :: forall n outer commons schemas params from grp ty. (PGTyped schemas ty, HasParameter n params ty) => Expression outer commons grp schemas params from ty
+ Squeal.PostgreSQL.Expression.Parameter: param :: forall n ty lat with db params from grp. (NullTyped db ty, HasParameter n params ty) => Expression grp lat with db params from ty
- Squeal.PostgreSQL.Expression.Parameter: parameter :: HasParameter n params ty => TypeExpression schemas ty -> Expression outer commons grp schemas params from ty
+ Squeal.PostgreSQL.Expression.Parameter: parameter :: HasParameter n params ty => TypeExpression db ty -> Expression grp lat with db params from ty
- Squeal.PostgreSQL.Expression.Sort: [AscNullsFirst] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: [AscNullsFirst] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: [AscNullsLast] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: [AscNullsLast] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: [Asc] :: Expression outer commons grp schemas params from ( 'NotNull ty) -> SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: [Asc] :: Expression grp lat with db params from ( 'NotNull ty) -> SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: [DescNullsFirst] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: [DescNullsFirst] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: [DescNullsLast] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: [DescNullsLast] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: [Desc] :: Expression outer commons grp schemas params from ( 'NotNull ty) -> SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: [Desc] :: Expression grp lat with db params from ( 'NotNull ty) -> SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: class OrderBy expr
+ Squeal.PostgreSQL.Expression.Sort: class OrderBy expr grp | expr -> grp
- Squeal.PostgreSQL.Expression.Sort: data SortExpression outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: data SortExpression grp lat with db params from
- Squeal.PostgreSQL.Expression.Sort: orderBy :: OrderBy expr => [SortExpression outer commons grp schemas params from] -> expr outer commons grp schemas params from -> expr outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Sort: orderBy :: OrderBy expr grp => [SortExpression grp lat with db params from] -> expr lat with db params from -> expr lat with db params from
- Squeal.PostgreSQL.Expression.Subquery: exists :: Query (Join outer from) commons schemas params row -> Condition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Subquery: exists :: Query (Join lat from) with db params row -> Expression grp lat with db params from (null 'PGbool)
- Squeal.PostgreSQL.Expression.Subquery: in_ :: Expression outer commons grp schemas params from ty -> [Expression outer commons grp schemas params from ty] -> Condition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Subquery: in_ :: Expression grp lat with db params from ty -> [Expression grp lat with db params from ty] -> Expression grp lat with db params from (null 'PGbool)
- Squeal.PostgreSQL.Expression.Subquery: notIn :: Expression outer commons grp schemas params from ty -> [Expression outer commons grp schemas params from ty] -> Condition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Subquery: notIn :: Expression grp lat with db params from ty -> [Expression grp lat with db params from ty] -> Expression grp lat with db params from (null 'PGbool)
- Squeal.PostgreSQL.Expression.Subquery: subAll :: Expression outer commons grp schemas params from ty1 -> Operator ty1 ty2 ( 'Null 'PGbool) -> Query (Join outer from) commons schemas params '[col ::: ty2] -> Condition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Subquery: subAll :: Expression grp lat with db params from ty1 -> Operator ty1 ty2 ( 'Null 'PGbool) -> Query (Join lat from) with db params '[col ::: ty2] -> Condition grp lat with db params from
- Squeal.PostgreSQL.Expression.Subquery: subAny :: Expression outer commons grp schemas params from ty1 -> Operator ty1 ty2 ( 'Null 'PGbool) -> Query (Join outer from) commons schemas params '[col ::: ty2] -> Condition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Subquery: subAny :: Expression grp lat with db params from ty1 -> Operator ty1 ty2 ( 'Null 'PGbool) -> Query (Join lat from) with db params '[col ::: ty2] -> Condition grp lat with db params from
- Squeal.PostgreSQL.Expression.Text: charLength :: null 'PGtext :--> null 'PGint4
+ Squeal.PostgreSQL.Expression.Text: charLength :: null 'PGtext --> null 'PGint4
- Squeal.PostgreSQL.Expression.Text: lower :: null 'PGtext :--> null 'PGtext
+ Squeal.PostgreSQL.Expression.Text: lower :: null 'PGtext --> null 'PGtext
- Squeal.PostgreSQL.Expression.Text: upper :: null 'PGtext :--> null 'PGtext
+ Squeal.PostgreSQL.Expression.Text: upper :: null 'PGtext --> null 'PGtext
- Squeal.PostgreSQL.Expression.TextSearch: (.!) :: null 'PGtsquery :--> null 'PGtsquery
+ Squeal.PostgreSQL.Expression.TextSearch: (.!) :: null 'PGtsquery --> null 'PGtsquery
- Squeal.PostgreSQL.Expression.TextSearch: arrayToTSvector :: null ( 'PGvararray ( 'NotNull 'PGtext)) :--> null 'PGtsvector
+ Squeal.PostgreSQL.Expression.TextSearch: arrayToTSvector :: null ( 'PGvararray ( 'NotNull 'PGtext)) --> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: jsonToTSvector :: FunctionN '[null 'PGjson, null 'PGjson] (null 'PGtsvector)
+ Squeal.PostgreSQL.Expression.TextSearch: jsonToTSvector :: '[null 'PGjson, null 'PGjson] ---> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: jsonbToTSvector :: FunctionN '[null 'PGjsonb, null 'PGjsonb] (null 'PGtsvector)
+ Squeal.PostgreSQL.Expression.TextSearch: jsonbToTSvector :: '[null 'PGjsonb, null 'PGjsonb] ---> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: numnode :: null 'PGtsquery :--> null 'PGint4
+ Squeal.PostgreSQL.Expression.TextSearch: numnode :: null 'PGtsquery --> null 'PGint4
- Squeal.PostgreSQL.Expression.TextSearch: phraseToTSquery :: null 'PGtext :--> null 'PGtsquery
+ Squeal.PostgreSQL.Expression.TextSearch: phraseToTSquery :: null 'PGtext --> null 'PGtsquery
- Squeal.PostgreSQL.Expression.TextSearch: plainToTSquery :: null 'PGtext :--> null 'PGtsquery
+ Squeal.PostgreSQL.Expression.TextSearch: plainToTSquery :: null 'PGtext --> null 'PGtsquery
- Squeal.PostgreSQL.Expression.TextSearch: queryTree :: null 'PGtsquery :--> null 'PGtext
+ Squeal.PostgreSQL.Expression.TextSearch: queryTree :: null 'PGtsquery --> null 'PGtext
- Squeal.PostgreSQL.Expression.TextSearch: setWeight :: FunctionN '[null 'PGtsvector, null ( 'PGchar 1)] (null 'PGtsvector)
+ Squeal.PostgreSQL.Expression.TextSearch: setWeight :: '[null 'PGtsvector, null ( 'PGchar 1)] ---> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: strip :: null 'PGtsvector :--> null 'PGtsvector
+ Squeal.PostgreSQL.Expression.TextSearch: strip :: null 'PGtsvector --> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: toTSquery :: null 'PGtext :--> null 'PGtsquery
+ Squeal.PostgreSQL.Expression.TextSearch: toTSquery :: null 'PGtext --> null 'PGtsquery
- Squeal.PostgreSQL.Expression.TextSearch: toTSvector :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => null ty :--> null 'PGtsvector
+ Squeal.PostgreSQL.Expression.TextSearch: toTSvector :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => null ty --> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: tsDelete :: FunctionN '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull 'PGtext))] (null 'PGtsvector)
+ Squeal.PostgreSQL.Expression.TextSearch: tsDelete :: '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull 'PGtext))] ---> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: tsFilter :: FunctionN '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull ( 'PGchar 1)))] (null 'PGtsvector)
+ Squeal.PostgreSQL.Expression.TextSearch: tsFilter :: '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull ( 'PGchar 1)))] ---> null 'PGtsvector
- Squeal.PostgreSQL.Expression.TextSearch: tsHeadline :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => FunctionN '[null document, null 'PGtsquery] (null 'PGtext)
+ Squeal.PostgreSQL.Expression.TextSearch: tsHeadline :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => '[null document, null 'PGtsquery] ---> null 'PGtext
- Squeal.PostgreSQL.Expression.TextSearch: tsvectorLength :: null 'PGtsvector :--> null 'PGint4
+ Squeal.PostgreSQL.Expression.TextSearch: tsvectorLength :: null 'PGtsvector --> null 'PGint4
- Squeal.PostgreSQL.Expression.TextSearch: websearchToTSquery :: null 'PGtext :--> null 'PGtsquery
+ Squeal.PostgreSQL.Expression.TextSearch: websearchToTSquery :: null 'PGtext --> null 'PGtsquery
- Squeal.PostgreSQL.Expression.Time: interval_ :: Double -> TimeUnit -> Expr (null 'PGinterval)
+ Squeal.PostgreSQL.Expression.Time: interval_ :: Milli -> TimeUnit -> Expr (null 'PGinterval)
- Squeal.PostgreSQL.Expression.Time: makeDate :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGint4] (null 'PGdate)
+ Squeal.PostgreSQL.Expression.Time: makeDate :: '[null 'PGint4, null 'PGint4, null 'PGint4] ---> null 'PGdate
- Squeal.PostgreSQL.Expression.Time: makeTime :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGfloat8] (null 'PGtime)
+ Squeal.PostgreSQL.Expression.Time: makeTime :: '[null 'PGint4, null 'PGint4, null 'PGfloat8] ---> null 'PGtime
- Squeal.PostgreSQL.Expression.Time: makeTimestamp :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] (null 'PGtimestamp)
+ Squeal.PostgreSQL.Expression.Time: makeTimestamp :: '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] ---> null 'PGtimestamp
- Squeal.PostgreSQL.Expression.Time: makeTimestamptz :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] (null 'PGtimestamptz)
+ Squeal.PostgreSQL.Expression.Time: makeTimestamptz :: '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] ---> null 'PGtimestamptz
- Squeal.PostgreSQL.Expression.Type: astype :: TypeExpression schemas ty -> Expression outer commons grp schemas params from ty -> Expression outer commons grp schemas params from ty
+ Squeal.PostgreSQL.Expression.Type: astype :: TypeExpression db ty -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty
- Squeal.PostgreSQL.Expression.Type: bigint :: TypeExpression schemas (null 'PGint8)
+ Squeal.PostgreSQL.Expression.Type: bigint :: TypeExpression db (null 'PGint8)
- Squeal.PostgreSQL.Expression.Type: bool :: TypeExpression schemas (null 'PGbool)
+ Squeal.PostgreSQL.Expression.Type: bool :: TypeExpression db (null 'PGbool)
- Squeal.PostgreSQL.Expression.Type: bytea :: TypeExpression schemas (null 'PGbytea)
+ Squeal.PostgreSQL.Expression.Type: bytea :: TypeExpression db (null 'PGbytea)
- Squeal.PostgreSQL.Expression.Type: cast :: TypeExpression schemas ty1 -> Expression outer commons grp schemas params from ty0 -> Expression outer commons grp schemas params from ty1
+ Squeal.PostgreSQL.Expression.Type: cast :: TypeExpression db ty1 -> Expression grp lat with db params from ty0 -> Expression grp lat with db params from ty1
- Squeal.PostgreSQL.Expression.Type: char :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGchar n))
+ Squeal.PostgreSQL.Expression.Type: char :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGchar n))
- Squeal.PostgreSQL.Expression.Type: character :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGchar n))
+ Squeal.PostgreSQL.Expression.Type: character :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGchar n))
- Squeal.PostgreSQL.Expression.Type: characterVarying :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGvarchar n))
+ Squeal.PostgreSQL.Expression.Type: characterVarying :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGvarchar n))
- Squeal.PostgreSQL.Expression.Type: class PGTyped schemas (ty :: NullityType)
+ Squeal.PostgreSQL.Expression.Type: class PGTyped db (ty :: PGType)
- Squeal.PostgreSQL.Expression.Type: date :: TypeExpression schemas (null 'PGdate)
+ Squeal.PostgreSQL.Expression.Type: date :: TypeExpression db (null 'PGdate)
- Squeal.PostgreSQL.Expression.Type: doublePrecision :: TypeExpression schemas (null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Type: doublePrecision :: TypeExpression db (null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Type: fixarray :: forall dims schemas null pg. All KnownNat dims => TypeExpression schemas pg -> TypeExpression schemas (null ( 'PGfixarray dims pg))
+ Squeal.PostgreSQL.Expression.Type: fixarray :: forall dims db null pg. All KnownNat dims => TypeExpression db pg -> TypeExpression db (null ( 'PGfixarray dims pg))
- Squeal.PostgreSQL.Expression.Type: float4 :: TypeExpression schemas (null 'PGfloat4)
+ Squeal.PostgreSQL.Expression.Type: float4 :: TypeExpression db (null 'PGfloat4)
- Squeal.PostgreSQL.Expression.Type: float8 :: TypeExpression schemas (null 'PGfloat8)
+ Squeal.PostgreSQL.Expression.Type: float8 :: TypeExpression db (null 'PGfloat8)
- Squeal.PostgreSQL.Expression.Type: inet :: TypeExpression schemas (null 'PGinet)
+ Squeal.PostgreSQL.Expression.Type: inet :: TypeExpression db (null 'PGinet)
- Squeal.PostgreSQL.Expression.Type: inferredtype :: PGTyped schemas ty => Expression outer common grp schemas params from ty -> Expression outer common grp schemas params from ty
+ Squeal.PostgreSQL.Expression.Type: inferredtype :: NullTyped db ty => Expression lat common grp db params from ty -> Expression lat common grp db params from ty
- Squeal.PostgreSQL.Expression.Type: int :: TypeExpression schemas (null 'PGint4)
+ Squeal.PostgreSQL.Expression.Type: int :: TypeExpression db (null 'PGint4)
- Squeal.PostgreSQL.Expression.Type: int2 :: TypeExpression schemas (null 'PGint2)
+ Squeal.PostgreSQL.Expression.Type: int2 :: TypeExpression db (null 'PGint2)
- Squeal.PostgreSQL.Expression.Type: int4 :: TypeExpression schemas (null 'PGint4)
+ Squeal.PostgreSQL.Expression.Type: int4 :: TypeExpression db (null 'PGint4)
- Squeal.PostgreSQL.Expression.Type: int8 :: TypeExpression schemas (null 'PGint8)
+ Squeal.PostgreSQL.Expression.Type: int8 :: TypeExpression db (null 'PGint8)
- Squeal.PostgreSQL.Expression.Type: integer :: TypeExpression schemas (null 'PGint4)
+ Squeal.PostgreSQL.Expression.Type: integer :: TypeExpression db (null 'PGint4)
- Squeal.PostgreSQL.Expression.Type: interval :: TypeExpression schemas (null 'PGinterval)
+ Squeal.PostgreSQL.Expression.Type: interval :: TypeExpression db (null 'PGinterval)
- Squeal.PostgreSQL.Expression.Type: json :: TypeExpression schemas (null 'PGjson)
+ Squeal.PostgreSQL.Expression.Type: json :: TypeExpression db (null 'PGjson)
- Squeal.PostgreSQL.Expression.Type: jsonb :: TypeExpression schemas (null 'PGjsonb)
+ Squeal.PostgreSQL.Expression.Type: jsonb :: TypeExpression db (null 'PGjsonb)
- Squeal.PostgreSQL.Expression.Type: newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)
+ Squeal.PostgreSQL.Expression.Type: newtype TypeExpression (db :: SchemasType) (ty :: NullType)
- Squeal.PostgreSQL.Expression.Type: numeric :: TypeExpression schemas (null 'PGnumeric)
+ Squeal.PostgreSQL.Expression.Type: numeric :: TypeExpression db (null 'PGnumeric)
- Squeal.PostgreSQL.Expression.Type: pgtype :: PGTyped schemas ty => TypeExpression schemas ty
+ Squeal.PostgreSQL.Expression.Type: pgtype :: PGTyped db ty => TypeExpression db (null ty)
- Squeal.PostgreSQL.Expression.Type: real :: TypeExpression schemas (null 'PGfloat4)
+ Squeal.PostgreSQL.Expression.Type: real :: TypeExpression db (null 'PGfloat4)
- Squeal.PostgreSQL.Expression.Type: smallint :: TypeExpression schemas (null 'PGint2)
+ Squeal.PostgreSQL.Expression.Type: smallint :: TypeExpression db (null 'PGint2)
- Squeal.PostgreSQL.Expression.Type: text :: TypeExpression schemas (null 'PGtext)
+ Squeal.PostgreSQL.Expression.Type: text :: TypeExpression db (null 'PGtext)
- Squeal.PostgreSQL.Expression.Type: time :: TypeExpression schemas (null 'PGtime)
+ Squeal.PostgreSQL.Expression.Type: time :: TypeExpression db (null 'PGtime)
- Squeal.PostgreSQL.Expression.Type: timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)
+ Squeal.PostgreSQL.Expression.Type: timeWithTimeZone :: TypeExpression db (null 'PGtimetz)
- Squeal.PostgreSQL.Expression.Type: timestamp :: TypeExpression schemas (null 'PGtimestamp)
+ Squeal.PostgreSQL.Expression.Type: timestamp :: TypeExpression db (null 'PGtimestamp)
- Squeal.PostgreSQL.Expression.Type: timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)
+ Squeal.PostgreSQL.Expression.Type: timestampWithTimeZone :: TypeExpression db (null 'PGtimestamptz)
- Squeal.PostgreSQL.Expression.Type: tsquery :: TypeExpression schemas (null 'PGtsquery)
+ Squeal.PostgreSQL.Expression.Type: tsquery :: TypeExpression db (null 'PGtsquery)
- Squeal.PostgreSQL.Expression.Type: tsvector :: TypeExpression schemas (null 'PGtsvector)
+ Squeal.PostgreSQL.Expression.Type: tsvector :: TypeExpression db (null 'PGtsvector)
- Squeal.PostgreSQL.Expression.Type: typedef :: (Has sch schemas schema, Has td schema ( 'Typedef ty)) => QualifiedAlias sch td -> TypeExpression schemas (null ty)
+ Squeal.PostgreSQL.Expression.Type: typedef :: (Has sch db schema, Has td schema ( 'Typedef ty)) => QualifiedAlias sch td -> TypeExpression db (null ty)
- Squeal.PostgreSQL.Expression.Type: typetable :: (Has sch schemas schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> TypeExpression schemas (null ( 'PGcomposite (TableToRow table)))
+ Squeal.PostgreSQL.Expression.Type: typetable :: (Has sch db schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> TypeExpression db (null ( 'PGcomposite (TableToRow table)))
- Squeal.PostgreSQL.Expression.Type: typeview :: (Has sch schemas schema, Has vw schema ( 'View view)) => QualifiedAlias sch vw -> TypeExpression schemas (null ( 'PGcomposite view))
+ Squeal.PostgreSQL.Expression.Type: typeview :: (Has sch db schema, Has vw schema ( 'View view)) => QualifiedAlias sch vw -> TypeExpression db (null ( 'PGcomposite view))
- Squeal.PostgreSQL.Expression.Type: uuid :: TypeExpression schemas (null 'PGuuid)
+ Squeal.PostgreSQL.Expression.Type: uuid :: TypeExpression db (null 'PGuuid)
- Squeal.PostgreSQL.Expression.Type: vararray :: TypeExpression schemas pg -> TypeExpression schemas (null ( 'PGvararray pg))
+ Squeal.PostgreSQL.Expression.Type: vararray :: TypeExpression db pg -> TypeExpression db (null ( 'PGvararray pg))
- Squeal.PostgreSQL.Expression.Type: varchar :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGvarchar n))
+ Squeal.PostgreSQL.Expression.Type: varchar :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGvarchar n))
- Squeal.PostgreSQL.Expression.Window: [WindowDefinition] :: SListI bys => NP (Expression outer commons grp schemas params from) bys -> [SortExpression outer commons grp schemas params from] -> WindowDefinition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Window: [WindowDefinition] :: SListI bys => NP (Expression grp lat with db params from) bys -> [SortExpression grp lat with db params from] -> WindowDefinition grp lat with db params from
- Squeal.PostgreSQL.Expression.Window: data WindowDefinition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Window: data WindowDefinition grp lat with db params from
- Squeal.PostgreSQL.Expression.Window: firstValue :: WinFun1 ty ty
+ Squeal.PostgreSQL.Expression.Window: firstValue :: ty -#-> ty
- Squeal.PostgreSQL.Expression.Window: lag :: WinFunN '[ty, 'NotNull 'PGint4, ty] ty
+ Squeal.PostgreSQL.Expression.Window: lag :: '[ty, 'NotNull 'PGint4, ty] --#-> ty
- Squeal.PostgreSQL.Expression.Window: lastValue :: WinFun1 ty ty
+ Squeal.PostgreSQL.Expression.Window: lastValue :: ty -#-> ty
- Squeal.PostgreSQL.Expression.Window: lead :: WinFunN '[ty, 'NotNull 'PGint4, ty] ty
+ Squeal.PostgreSQL.Expression.Window: lead :: '[ty, 'NotNull 'PGint4, ty] --#-> ty
- Squeal.PostgreSQL.Expression.Window: newtype WindowFunction (outer :: FromType) (commons :: FromType) (grp :: Grouping) (schemas :: SchemasType) (params :: [NullityType]) (from :: FromType) (ty :: NullityType)
+ Squeal.PostgreSQL.Expression.Window: newtype WindowFunction (grp :: Grouping) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType) (ty :: NullType)
- Squeal.PostgreSQL.Expression.Window: nthValue :: WinFunN '[null ty, 'NotNull 'PGint4] ( 'Null ty)
+ Squeal.PostgreSQL.Expression.Window: nthValue :: '[null ty, 'NotNull 'PGint4] --#-> 'Null ty
- Squeal.PostgreSQL.Expression.Window: ntile :: WinFun1 ( 'NotNull 'PGint4) ( 'NotNull 'PGint4)
+ Squeal.PostgreSQL.Expression.Window: ntile :: 'NotNull 'PGint4 -#-> 'NotNull 'PGint4
- Squeal.PostgreSQL.Expression.Window: partitionBy :: SListI bys => NP (Expression outer commons grp schemas params from) bys -> WindowDefinition outer commons grp schemas params from
+ Squeal.PostgreSQL.Expression.Window: partitionBy :: SListI bys => NP (Expression grp lat with db params from) bys -> WindowDefinition grp lat with db params from
- Squeal.PostgreSQL.Expression.Window: type WinFun0 x = forall outer commons grp schemas params from. WindowFunction outer commons grp schemas params from x " cannot reference aliases"
+ Squeal.PostgreSQL.Expression.Window: type WinFun0 x = forall grp lat with db params from. WindowFunction grp lat with db params from x " cannot reference aliases"
- Squeal.PostgreSQL.Expression.Window: unsafeWindowFunction1 :: ByteString -> WinFun1 x y
+ Squeal.PostgreSQL.Expression.Window: unsafeWindowFunction1 :: ByteString -> x -#-> y
- Squeal.PostgreSQL.Expression.Window: unsafeWindowFunctionN :: SListI xs => ByteString -> WinFunN xs y
+ Squeal.PostgreSQL.Expression.Window: unsafeWindowFunctionN :: SListI xs => ByteString -> xs --#-> y
- Squeal.PostgreSQL.Manipulation: Returning :: Selection '[] commons 'Ungrouped schemas params from row -> ReturningClause commons schemas params from row
+ Squeal.PostgreSQL.Manipulation: Returning :: Selection 'Ungrouped '[] with db params from row -> ReturningClause with db params from row
- Squeal.PostgreSQL.Manipulation: newtype Manipulation (commons :: FromType) (schemas :: SchemasType) (params :: [NullityType]) (columns :: RowType)
+ Squeal.PostgreSQL.Manipulation: newtype Manipulation (with :: FromType) (db :: SchemasType) (params :: [NullType]) (columns :: RowType)
- Squeal.PostgreSQL.Manipulation: newtype ReturningClause commons schemas params from row
+ Squeal.PostgreSQL.Manipulation: newtype ReturningClause with db params from row
- Squeal.PostgreSQL.Manipulation: pattern Returning_ :: SListI row => NP (Aliased (Expression '[] commons 'Ungrouped schemas params from)) row -> ReturningClause commons schemas params from row
+ Squeal.PostgreSQL.Manipulation: pattern Returning_ :: SListI row => NP (Aliased (Expression 'Ungrouped '[] with db params from)) row -> ReturningClause with db params from row
- Squeal.PostgreSQL.Manipulation: queryStatement :: Query '[] commons schemas params columns -> Manipulation commons schemas params columns
+ Squeal.PostgreSQL.Manipulation: queryStatement :: Query '[] with db params columns -> Manipulation with db params columns
- Squeal.PostgreSQL.Manipulation: type family Manipulation_ (schemas :: SchemasType) (params :: Type) (row :: Type)
+ Squeal.PostgreSQL.Manipulation: type family Manipulation_ (db :: SchemasType) (params :: Type) (row :: Type)
- Squeal.PostgreSQL.Query: except :: Query outer commons schemas params columns -> Query outer commons schemas params columns -> Query outer commons schemas params columns
+ Squeal.PostgreSQL.Query: except :: Query lat with db params columns -> Query lat with db params columns -> Query lat with db params columns
- Squeal.PostgreSQL.Query: exceptAll :: Query outer commons schemas params columns -> Query outer commons schemas params columns -> Query outer commons schemas params columns
+ Squeal.PostgreSQL.Query: exceptAll :: Query lat with db params columns -> Query lat with db params columns -> Query lat with db params columns
- Squeal.PostgreSQL.Query: intersect :: Query outer commons schemas params columns -> Query outer commons schemas params columns -> Query outer commons schemas params columns
+ Squeal.PostgreSQL.Query: intersect :: Query lat with db params columns -> Query lat with db params columns -> Query lat with db params columns
- Squeal.PostgreSQL.Query: intersectAll :: Query outer commons schemas params columns -> Query outer commons schemas params columns -> Query outer commons schemas params columns
+ Squeal.PostgreSQL.Query: intersectAll :: Query lat with db params columns -> Query lat with db params columns -> Query lat with db params columns
- Squeal.PostgreSQL.Query: newtype Query (outer :: FromType) (commons :: FromType) (schemas :: SchemasType) (params :: [NullityType]) (row :: RowType)
+ Squeal.PostgreSQL.Query: newtype Query (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (row :: RowType)
- Squeal.PostgreSQL.Query: type family Query_ (schemas :: SchemasType) (parameters :: Type) (row :: Type)
+ Squeal.PostgreSQL.Query: type family Query_ (db :: SchemasType) (params :: Type) (row :: Type)
- Squeal.PostgreSQL.Query: union :: Query outer commons schemas params columns -> Query outer commons schemas params columns -> Query outer commons schemas params columns
+ Squeal.PostgreSQL.Query: union :: Query lat with db params columns -> Query lat with db params columns -> Query lat with db params columns
- Squeal.PostgreSQL.Query: unionAll :: Query outer commons schemas params columns -> Query outer commons schemas params columns -> Query outer commons schemas params columns
+ Squeal.PostgreSQL.Query: unionAll :: Query lat with db params columns -> Query lat with db params columns -> Query lat with db params columns
Files
- bench/Gauge.hs +116/−0
- bench/Gauge/DBHelpers.hs +73/−0
- bench/Gauge/DBSetup.hs +136/−0
- bench/Gauge/Queries.hs +149/−0
- bench/Gauge/Schema.hs +93/−0
- exe/Example.hs +16/−10
- squeal-postgresql.cabal +102/−23
- src/Squeal/PostgreSQL.hs +72/−39
- src/Squeal/PostgreSQL/Alias.hs +0/−249
- src/Squeal/PostgreSQL/Binary.hs +0/−757
- src/Squeal/PostgreSQL/Definition.hs +85/−1108
- src/Squeal/PostgreSQL/Definition/Constraint.hs +341/−0
- src/Squeal/PostgreSQL/Definition/Function.hs +249/−0
- src/Squeal/PostgreSQL/Definition/Index.hs +186/−0
- src/Squeal/PostgreSQL/Definition/Schema.hs +113/−0
- src/Squeal/PostgreSQL/Definition/Table.hs +497/−0
- src/Squeal/PostgreSQL/Definition/Type.hs +247/−0
- src/Squeal/PostgreSQL/Definition/View.hs +135/−0
- src/Squeal/PostgreSQL/Expression.hs +367/−116
- src/Squeal/PostgreSQL/Expression/Aggregate.hs +258/−174
- src/Squeal/PostgreSQL/Expression/Array.hs +139/−0
- src/Squeal/PostgreSQL/Expression/Collection.hs +0/−169
- src/Squeal/PostgreSQL/Expression/Comparison.hs +26/−22
- src/Squeal/PostgreSQL/Expression/Composite.hs +93/−0
- src/Squeal/PostgreSQL/Expression/Default.hs +60/−0
- src/Squeal/PostgreSQL/Expression/Inline.hs +331/−0
- src/Squeal/PostgreSQL/Expression/Json.hs +71/−78
- src/Squeal/PostgreSQL/Expression/Literal.hs +0/−87
- src/Squeal/PostgreSQL/Expression/Logic.hs +23/−20
- src/Squeal/PostgreSQL/Expression/Math.hs +18/−19
- src/Squeal/PostgreSQL/Expression/Null.hs +37/−18
- src/Squeal/PostgreSQL/Expression/Parameter.hs +18/−17
- src/Squeal/PostgreSQL/Expression/Range.hs +227/−0
- src/Squeal/PostgreSQL/Expression/SetOf.hs +0/−106
- src/Squeal/PostgreSQL/Expression/Sort.hs +39/−23
- src/Squeal/PostgreSQL/Expression/Subquery.hs +23/−21
- src/Squeal/PostgreSQL/Expression/Text.hs +13/−12
- src/Squeal/PostgreSQL/Expression/TextSearch.hs +27/−26
- src/Squeal/PostgreSQL/Expression/Time.hs +25/−26
- src/Squeal/PostgreSQL/Expression/Type.hs +287/−89
- src/Squeal/PostgreSQL/Expression/Window.hs +138/−94
- src/Squeal/PostgreSQL/List.hs +0/−141
- src/Squeal/PostgreSQL/Manipulation.hs +74/−351
- src/Squeal/PostgreSQL/Manipulation/Delete.hs +101/−0
- src/Squeal/PostgreSQL/Manipulation/Insert.hs +259/−0
- src/Squeal/PostgreSQL/Manipulation/Update.hs +97/−0
- src/Squeal/PostgreSQL/Migration.hs +0/−446
- src/Squeal/PostgreSQL/PG.hs +0/−365
- src/Squeal/PostgreSQL/PQ.hs +0/−688
- src/Squeal/PostgreSQL/Pool.hs +0/−122
- src/Squeal/PostgreSQL/Query.hs +72/−707
- src/Squeal/PostgreSQL/Query/From.hs +110/−0
- src/Squeal/PostgreSQL/Query/From/Join.hs +296/−0
- src/Squeal/PostgreSQL/Query/From/Set.hs +204/−0
- src/Squeal/PostgreSQL/Query/Select.hs +252/−0
- src/Squeal/PostgreSQL/Query/Table.hs +289/−0
- src/Squeal/PostgreSQL/Query/Values.hs +88/−0
- src/Squeal/PostgreSQL/Query/With.hs +123/−0
- src/Squeal/PostgreSQL/Render.hs +15/−5
- src/Squeal/PostgreSQL/Schema.hs +0/−449
- src/Squeal/PostgreSQL/Session.hs +295/−0
- src/Squeal/PostgreSQL/Session/Connection.hs +78/−0
- src/Squeal/PostgreSQL/Session/Decode.hs +445/−0
- src/Squeal/PostgreSQL/Session/Encode.hs +508/−0
- src/Squeal/PostgreSQL/Session/Exception.hs +96/−0
- src/Squeal/PostgreSQL/Session/Indexed.hs +126/−0
- src/Squeal/PostgreSQL/Session/Migration.hs +458/−0
- src/Squeal/PostgreSQL/Session/Monad.hs +267/−0
- src/Squeal/PostgreSQL/Session/Oid.hs +221/−0
- src/Squeal/PostgreSQL/Session/Pool.hs +124/−0
- src/Squeal/PostgreSQL/Session/Result.hs +182/−0
- src/Squeal/PostgreSQL/Session/Statement.hs +127/−0
- src/Squeal/PostgreSQL/Session/Transaction.hs +253/−0
- src/Squeal/PostgreSQL/Transaction.hs +0/−252
- src/Squeal/PostgreSQL/Type.hs +161/−0
- src/Squeal/PostgreSQL/Type/Alias.hs +260/−0
- src/Squeal/PostgreSQL/Type/List.hs +118/−0
- src/Squeal/PostgreSQL/Type/PG.hs +334/−0
- src/Squeal/PostgreSQL/Type/Schema.hs +612/−0
- test/Doc.hs +6/−0
- test/DocTest.hs +0/−18
- test/Property.hs +205/−0
- test/Spec.hs +212/−0
- test/Specs/ExceptionHandling.hs +0/−140
- test/Specs/Specs.hs +0/−7
+ bench/Gauge.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main where++import Squeal.PostgreSQL hiding ( defaultMain )+import Gauge.Main+import Gauge.Main.Options ( defaultConfig+ , Config(..)+ , Verbosity(..)+ , DisplayMode(..)+ , Mode(..)+ )+import GHC.Generics+import qualified Generics.SOP as SOP+import Test.QuickCheck+-- For CI+import Main.Utf8 ( withUtf8 )+-- For keeping a track of which question ID to query+import Data.Int ( Int64 )+import Data.IORef+-- Project imports+import Gauge.Schema+import Gauge.Queries+import Gauge.DBSetup ( teardownDB )+import Gauge.DBHelpers ( initDBWithPool+ , getRandomUser+ , runDbWithPool+ , SquealPool+ )++main :: IO ()+main = do+ -- A mutable hack here to keep track of+ -- pulling a new user by ID from the db instead of the same id+ currentId <- newIORef (1 :: UserId)++ -- Define benchmarks+ let+ queryRenderGroup :: Benchmark+ queryRenderGroup = bgroup+ "Render Queries"+ [ bench "createUser: weak head normal form" $ whnf renderSQL createUser+ , bench "createUser: normal form" $ nf renderSQL createUser+ , bench "userDetails: weak head normal form" $ whnf renderSQL userDetails+ , bench "userDetails: normal form" $ nf renderSQL userDetails+ , bench "insertDeviceDetails: weak head normal form"+ $ whnf renderSQL insertDeviceDetails+ , bench "insertDeviceDetails: normal form"+ $ nf renderSQL insertDeviceDetails+ ]++ -- Queries against an actual DB++ -- 1. Initialize Schema to DB+ -- 2. Make connection pool and pass it to tests+ -- 3. Generate users on the fly and add them to DB+ -- 4. Tear the Schema down from the DB++ dbInsertsGroup :: Benchmark+ dbInsertsGroup =+ envWithCleanup initDBWithPool (const teardownDB) $ \pool -> bgroup+ "Run individual INSERTs against DB using a connection pool"+ [ bgroup+ "INSERT: add users to the table users"+ [ bench "Run individual INSERT statement" $ makeRunOnce $ perRunEnv+ getRandomUser+ -- The actual action to benchmark+ (\(user :: InsertUser) ->+ runDbWithPool pool $ createUserSession user+ )+ ]+ ]++ dbSelectsGroup :: Benchmark+ dbSelectsGroup =+ envWithCleanup initDBWithPool (const teardownDB) $ \pool -> bgroup+ "Run individual SELECTs against DB using a connection pool"+ [ bgroup+ "SELECT: fetch users from the table users individually"+ [ bench "Fetch a single user" $ makeRunOnce $ perRunEnv+ (insertAndIncrement pool currentId)+ (\(id_ :: UserId) -> runDbWithPool pool $ userDetailsSession id_+ )+ ]+ ]++ withUtf8 $ defaultMain [queryRenderGroup, dbInsertsGroup, dbSelectsGroup]+++-- | Configure the benchmark to run only once (per IO action)+makeRunOnce :: Benchmarkable -> Benchmarkable+makeRunOnce current = current { perRun = True }++getAndIncrementId :: (IORef UserId) -> IO UserId+getAndIncrementId currentId = do+ current <- readIORef currentId+ writeIORef currentId (current + 1)+ return current++-- | This INSERTs a row in the db so that there's always a row to query.+-- Otherwise 'getRow 0' throws an exception.+-- NOTE: will make benchmark time slower but does not affect results.+insertAndIncrement :: SquealPool -> (IORef UserId) -> IO UserId+insertAndIncrement pool currentId = do+ user <- getRandomUser+ _ <- runDbWithPool pool $ createUserSession user+ getAndIncrementId currentId
+ bench/Gauge/DBHelpers.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}++module Gauge.DBHelpers where++import Data.ByteString ( ByteString )+import qualified Data.ByteString.Char8 as C+import qualified Data.Text as T+import Control.Monad ( void )+import Control.Monad.Except ( MonadIO+ , throwError+ )+import Control.Monad.IO.Class ( liftIO )+import Control.Monad.Loops ( iterateWhile )+import GHC.Generics ( Generic+ , Generic1+ )+import Test.QuickCheck+import Squeal.PostgreSQL+import qualified Data.ByteString.Char8 as C+import Control.DeepSeq+-- Project imports+import Gauge.Schema ( Schemas )+import Gauge.Queries ( InsertUser(..) )+import Gauge.DBSetup++newtype SquealPool = SquealPool {getSquealPool :: Pool (K Connection Schemas)} deriving (Generic)+-- Below may be wrong - it may screw up the whole connection pool using in tests+instance NFData SquealPool where+ rnf = rwhnf++runDbErr+ :: SquealPool -> PQ Schemas Schemas IO b -> IO (Either SquealException b)+runDbErr pool session = do+ liftIO . runUsingConnPool pool $ trySqueal (transactionally_ session)++runDbWithPool :: SquealPool -> PQ Schemas Schemas IO b -> IO b+runDbWithPool pool session = do+ errOrResult <- runDbErr pool session+ case errOrResult of+ Left err -> throwSqueal err+ Right result -> return result++-- | Helper+runUsingConnPool :: SquealPool -> PQ Schemas Schemas IO x -> IO x+runUsingConnPool (SquealPool pool) = usingConnectionPool pool++makePool :: C.ByteString -> IO SquealPool+makePool connStr = do+ pool <- createConnectionPool connStr 1 0.5 10+ return $ SquealPool pool++initDBWithPool :: IO SquealPool+initDBWithPool = do+ void initDB+ pool <- makePool connectionString+ return pool++getRandomUser :: IO InsertUser+getRandomUser = iterateWhile noEmptyEmail $ generate arbitrary+ where+ noEmptyEmail InsertUser { userEmail = userEmail } = T.length userEmail < 5
+ bench/Gauge/DBSetup.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Gauge.DBSetup where++import Data.ByteString ( ByteString )+import qualified Data.ByteString.Char8 as C+import Control.Monad ( void )+import GHC.Generics+import Test.QuickCheck+import Squeal.PostgreSQL+-- Project imports+import Gauge.Schema ( Schemas+ , DeviceOS+ , IPLocation+ )+import Gauge.Queries ( InsertUser )+++-- First create enums as they're needed in the Schema+setup :: Definition (Public '[]) Schemas+setup =+ createTypeEnumFrom @DeviceOS #device_os+ >>> createTypeCompositeFrom @IPLocation #ip_location+ >>> createTable+ #users+ ( serial8+ `as` #id+ :* (text & notNullable)+ `as` #email+ :* (text & notNullable)+ `as` #password+ :* (text & nullable)+ `as` #first_name+ :* (int2 & nullable)+ `as` #birthyear+ )+ (primaryKey #id `as` #pk_users :* unique #email `as` #email)+ >>> createTable+ #user_devices+ ( serial8+ `as` #id+ :* notNullable int8+ `as` #user_id+ :* (text & notNullable)+ `as` #token+ :* (typedef #device_os & notNullable)+ `as` #os+ )+ ( primaryKey #id+ `as` #pk_user_devices+ :* foreignKey #user_id #users #id OnDeleteCascade OnUpdateCascade+ `as` #fk_user_id+ :* unique #token+ `as` #token+ )++-- Drop types last because tables depend on them+teardown :: Definition Schemas (Public '[])+teardown =+ dropTableCascade #user_devices+ >>> dropTableCascade #users+ >>> dropType #ip_location+ >>> dropType #device_os++-- With env vars, we could use the commented keys+data PGConfig = PGConfig+ { pgHost :: String -- "PG_HOST"+ , pgPort :: Int -- "PG_PORT"+ , pgDbname :: String -- "PG_DBNAME" + , pgUser :: String -- "PG_USER"+ , pgPassword :: String -- "PG_PASSWORD" + }+ deriving (Generic, Show)++-- | Helper: unused now, but primarily for testing locally+makeConnStr :: PGConfig -> ByteString+makeConnStr PGConfig { pgHost = host, pgPort = portNumber, pgDbname = dbName, pgUser = user, pgPassword = pw }+ = C.pack+ $ "host="+ <> host+ <> " dbname="+ <> dbName+ <> " user="+ <> user+ <> " password="+ <> pw+ <> " port="+ <> show portNumber++connectionString :: ByteString+connectionString = "host=localhost port=5432 dbname=exampledb"++performDBAction :: Definition a b -> String -> IO ()+performDBAction action message = do+ void+ $ withConnection connectionString+ $ manipulate_ (UnsafeManipulation "SET client_min_messages TO WARNING;")+ & pqThen (define action)+ putStrLn message++initDB :: IO ()+initDB =+ performDBAction setup "Initialized Schema & corresponding tables for Database"++teardownDB :: IO ()+teardownDB = performDBAction teardown "Dropped all database tables"++dbSchema :: Definition '["public" ::: '[]] (Drop "public" '["public" ::: '[]])+dbSchema = dropSchemaCascade #public++dropDBSchema :: IO ()+dropDBSchema = performDBAction dbSchema "Dropped Public schema from database"++-- | Concatenate two `ByteString`s with a space between.+(<+>) :: ByteString -> ByteString -> ByteString+infixr 7 <+>+str1 <+> str2 = str1 <> " " <> str2++-- | Drop table custom SQL statement with 'cascade'+dropTableCascade+ :: (Has sch schemas schema, Has tab schema ( 'Table table))+ => QualifiedAlias sch tab -- ^ table to remove+ -> Definition schemas (Alter sch (Drop tab schema) schemas)+dropTableCascade tab =+ UnsafeDefinition $ "DROP TABLE" <+> renderSQL tab <> " cascade;"
+ bench/Gauge/Queries.hs view
@@ -0,0 +1,149 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DerivingStrategies #-}++module Gauge.Queries where++import Squeal.PostgreSQL+import GHC.Generics ( Generic )+import qualified Generics.SOP as SOP+-- Need below for deriving instances+import Control.DeepSeq+import Data.Text ( Text )+import Data.Int ( Int16+ , Int64+ )+import Test.QuickCheck ( Arbitrary(..)+ , PrintableString(..)+ , listOf+ , arbitraryPrintableChar+ )+import Generic.Random ( genericArbitrarySingle )+-- Import Orphan instances+import Test.QuickCheck.Instances ( )+-- Project imports+import Gauge.Schema++-- Types++type UserId = Int64+-- Insert user+data InsertUser = InsertUser+ { userEmail :: Text+ , userPassword :: Text+ , userFirstName :: Maybe Text+ , userBirthyear :: Maybe Int16+ }+ deriving (Show, Eq, Generic, NFData)+instance SOP.Generic InsertUser+instance SOP.HasDatatypeInfo InsertUser+-- Arbitrary instances for producing values with quickcheck+instance Arbitrary InsertUser where+ arbitrary = genericArbitrarySingle++sampleInsertUser :: InsertUser+sampleInsertUser = InsertUser { userEmail = "mark@gmail.com"+ , userPassword = "MySecretPassword"+ , userFirstName = Just "Mark"+ , userBirthyear = Just 1980+ }++data APIDBUser_ = APIDBUser_+ { userId :: UserId+ , email :: Text+ , first_name :: Maybe Text+ , birthyear :: Maybe Int16+ }+ deriving (Show, Eq, Generic, NFData)+instance SOP.Generic APIDBUser_+instance SOP.HasDatatypeInfo APIDBUser_+-- Arbitrary instances for producing values with quickcheck+instance Arbitrary APIDBUser_ where+ arbitrary = genericArbitrarySingle++data Row3 a b c = Row4+ { col1 :: a+ , col2 :: b+ , col3 :: c+ }+ deriving stock Generic+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)++-- (UserId, Token, OS)+type DeviceDetailsRow = Row3 UserId Text (Enumerated DeviceOS)++-- -- Queries++createUserSession :: InsertUser -> PQ Schemas Schemas IO APIDBUser_+createUserSession insertUser =+ getRow 0 =<< manipulateParams createUser insertUser++createUser :: Manipulation_ Schemas InsertUser APIDBUser_+createUser = insertInto+ #users+ (Values_+ ( Default+ `as` #id+ :* Set (param @1)+ `as` #email+ :* Set (param @2)+ `as` #password+ :* Set (param @3)+ `as` #first_name+ :* Set (param @4 & cast int2)+ `as` #birthyear+ )+ )+ OnConflictDoRaise+ (Returning_+ ( #id+ `as` #userId+ :* #email+ `as` #email+ :* #first_name+ `as` #first_name+ :* #birthyear+ `as` #birthyear+ )+ )++userDetailsSession :: UserId -> PQ Schemas Schemas IO APIDBUser_+userDetailsSession uID = getRow 0 =<< runQueryParams userDetails (Only uID)++userDetails :: Query_ Schemas (Only UserId) APIDBUser_+userDetails = select_+ ( #id+ `as` #userId+ :* #email+ `as` #email+ :* #first_name+ `as` #first_name+ :* #birthyear+ `as` #birthyear+ )+ (from (table #users) & where_ (#id .== (param @1 & cast int8)))++insertDeviceDetails :: Manipulation_ Schemas DeviceDetailsRow ()+insertDeviceDetails = insertInto+ #user_devices+ (Values_+ ( Default+ `as` #id+ :* Set (param @1)+ `as` #user_id+ :* Set (param @2)+ `as` #token+ :* Set (parameter @3 (typedef #device_os))+ `as` #os+ )+ )+ OnConflictDoRaise+ (Returning_ Nil)
+ bench/Gauge/Schema.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DeriveGeneric #-}++module Gauge.Schema where++import Squeal.PostgreSQL+import GHC.Generics+import qualified Generics.SOP as SOP+++-- Type++data DeviceOS = Android | IOS+ deriving (Show, Read, Eq, Generic)+-- DeviceOS is converted to PG Enum type+instance SOP.Generic DeviceOS+instance SOP.HasDatatypeInfo DeviceOS++-- Defined extra types for the database+-- Operating system enum+type PGDeviceOS = PG (Enumerated DeviceOS)+type DeviceOSType = 'Typedef PGDeviceOS++-- For composite type+data IPLocation = IPLocation+ { countryShort :: String+ , region :: String+ , city :: String+ }+ deriving (Show, Read, Eq, Generic)++instance SOP.Generic IPLocation+instance SOP.HasDatatypeInfo IPLocation++-- IPLocation Composite type+type PGIPLocation = PG (Composite IPLocation)+type IPLocationType = 'Typedef PGIPLocation++-- SCHEMA++-- Users++type UsersColumns = '[+ "id" ::: 'Def :=> 'NotNull 'PGint8+ , "email" ::: 'NoDef :=> 'NotNull 'PGtext+ , "password" ::: 'NoDef :=> 'NotNull 'PGtext+ , "first_name" ::: 'NoDef :=> 'Null 'PGtext+ , "birthyear" ::: 'NoDef :=> 'Null 'PGint2+ ]++type UsersConstraints = '[+ "pk_users" ::: 'PrimaryKey '["id"]+ , "email" ::: 'Unique '["email"]+ ]++type UsersTable = 'Table (UsersConstraints :=> UsersColumns)++-- User devices+type UserDevicesColumns = '[+ "id" ::: 'Def :=> 'NotNull 'PGint8 -- ID as PK because user might have many same OS devices+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint8+ , "token" ::: 'NoDef :=> 'NotNull 'PGtext+ , "os" ::: 'NoDef :=> 'NotNull PGDeviceOS+ ]++type UserDevicesConstraints = '[+ "pk_user_devices" ::: 'PrimaryKey '["id"]+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]+ , "token" ::: 'Unique '["token"]+ ]++type UserDevicesTable = 'Table (UserDevicesConstraints :=> UserDevicesColumns)++-- Schema+-- Make sure to put types before tables, otherwise won't compile+type Schema = '[+ -- Enum types:+ "device_os" ::: DeviceOSType+ -- Composite types:+ , "ip_location" ::: IPLocationType+ -- Tables:+ , "users" ::: UsersTable+ , "user_devices" ::: UserDevicesTable+ ]++type Schemas = '["public" ::: Schema]
exe/Example.hs view
@@ -13,7 +13,6 @@ import Control.Monad.IO.Class (MonadIO (..)) import Data.Int (Int16, Int32)-import Data.Monoid ((<>)) import Data.Text (Text) import Data.Vector (Vector) @@ -38,6 +37,7 @@ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4 , "email" ::: 'NoDef :=> 'Null 'PGtext ])+ , "positive" ::: 'Typedef 'PGfloat4 ] type Schemas = Public Schema@@ -52,14 +52,16 @@ >>> createTable #emails ( serial `as` #id :*- (int & notNullable) `as` #user_id :*- (text & nullable) `as` #email )+ columntypeFrom @Int32 `as` #user_id :*+ columntypeFrom @(Maybe Text) `as` #email ) ( primaryKey #id `as` #pk_emails :* foreignKey #user_id #users #id OnDeleteCascade OnUpdateCascade `as` #fk_user_id )+ >>>+ createDomain #positive real (#value .> 0 .&& (#value & isNotNull)) teardown :: Definition Schemas (Public '[])-teardown = dropTable #emails >>> dropTable #users+teardown = dropType #positive >>> dropTable #emails >>> dropTable #users insertUser :: Manipulation_ Schemas (Text, VarArray (Vector (Maybe Int16))) (Only Int32) insertUser = insertInto #users@@ -77,23 +79,27 @@ & innerJoin (table (#emails `as` #e)) (#u ! #id .== #e ! #user_id)) ) -data User = User { userName :: Text, userEmail :: Maybe Text, userVec :: VarArray (Vector (Maybe Int16)) }- deriving (Show, GHC.Generic)+data User+ = User+ { userName :: Text+ , userEmail :: Maybe Text+ , userVec :: VarArray (Vector (Maybe Int16))+ } deriving (Show, GHC.Generic) instance SOP.Generic User instance SOP.HasDatatypeInfo User users :: [User] users =- [ User "Alice" (Just "alice@gmail.com") (VarArray [Nothing, Just 1])- , User "Bob" Nothing (VarArray [Just 2, Nothing])- , User "Carole" (Just "carole@hotmail.com") (VarArray [Just 3])+ [ User "Alice" (Just "alice@gmail.com") (VarArray [Just 1,Just 2,Nothing])+ , User "Bob" Nothing (VarArray [Nothing,Just (-3)])+ , User "Carole" (Just "carole@hotmail.com") (VarArray [Just 3,Nothing, Just 4]) ] session :: (MonadIO pq, MonadPQ Schemas pq) => pq () session = do liftIO $ Char8.putStrLn "manipulating" idResults <- traversePrepared insertUser ([(userName user, userVec user) | user <- users])- ids <- traverse (fmap fromOnly . getRow 0) idResults+ ids <- traverse (fmap fromOnly . getRow 0) (idResults :: [Result (Only Int32)]) traversePrepared_ insertEmail (zip (ids :: [Int32]) (userEmail <$> users)) liftIO $ Char8.putStrLn "querying" usersResult <- runQuery getUsers
squeal-postgresql.cabal view
@@ -1,5 +1,5 @@ name: squeal-postgresql-version: 0.5.2.0+version: 0.6.0.0 synopsis: Squeal PostgreSQL Library description: Squeal is a type-safe embedding of PostgreSQL in Haskell homepage: https://github.com/morphismtech/squeal@@ -22,20 +22,27 @@ hs-source-dirs: src exposed-modules: Squeal.PostgreSQL- Squeal.PostgreSQL.Alias- Squeal.PostgreSQL.Binary Squeal.PostgreSQL.Definition+ Squeal.PostgreSQL.Definition.Constraint+ Squeal.PostgreSQL.Definition.Function+ Squeal.PostgreSQL.Definition.Index+ Squeal.PostgreSQL.Definition.Table+ Squeal.PostgreSQL.Definition.Type+ Squeal.PostgreSQL.Definition.Schema+ Squeal.PostgreSQL.Definition.View Squeal.PostgreSQL.Expression Squeal.PostgreSQL.Expression.Aggregate- Squeal.PostgreSQL.Expression.Collection+ Squeal.PostgreSQL.Expression.Array Squeal.PostgreSQL.Expression.Comparison+ Squeal.PostgreSQL.Expression.Composite+ Squeal.PostgreSQL.Expression.Default Squeal.PostgreSQL.Expression.Json- Squeal.PostgreSQL.Expression.Literal+ Squeal.PostgreSQL.Expression.Inline Squeal.PostgreSQL.Expression.Logic Squeal.PostgreSQL.Expression.Math Squeal.PostgreSQL.Expression.Null Squeal.PostgreSQL.Expression.Parameter- Squeal.PostgreSQL.Expression.SetOf+ Squeal.PostgreSQL.Expression.Range Squeal.PostgreSQL.Expression.Sort Squeal.PostgreSQL.Expression.Subquery Squeal.PostgreSQL.Expression.Text@@ -43,31 +50,55 @@ Squeal.PostgreSQL.Expression.Time Squeal.PostgreSQL.Expression.Type Squeal.PostgreSQL.Expression.Window- Squeal.PostgreSQL.List Squeal.PostgreSQL.Manipulation- Squeal.PostgreSQL.Migration- Squeal.PostgreSQL.Pool- Squeal.PostgreSQL.PG- Squeal.PostgreSQL.PQ+ Squeal.PostgreSQL.Manipulation.Delete+ Squeal.PostgreSQL.Manipulation.Insert+ Squeal.PostgreSQL.Manipulation.Update Squeal.PostgreSQL.Render Squeal.PostgreSQL.Query- Squeal.PostgreSQL.Schema- Squeal.PostgreSQL.Transaction+ Squeal.PostgreSQL.Query.From+ Squeal.PostgreSQL.Query.From.Join+ Squeal.PostgreSQL.Query.From.Set+ Squeal.PostgreSQL.Query.Select+ Squeal.PostgreSQL.Query.Table+ Squeal.PostgreSQL.Query.Values+ Squeal.PostgreSQL.Query.With+ Squeal.PostgreSQL.Session+ Squeal.PostgreSQL.Session.Connection+ Squeal.PostgreSQL.Session.Decode+ Squeal.PostgreSQL.Session.Encode+ Squeal.PostgreSQL.Session.Exception+ Squeal.PostgreSQL.Session.Indexed+ Squeal.PostgreSQL.Session.Migration+ Squeal.PostgreSQL.Session.Monad+ Squeal.PostgreSQL.Session.Oid+ Squeal.PostgreSQL.Session.Pool+ Squeal.PostgreSQL.Session.Result+ Squeal.PostgreSQL.Session.Statement+ Squeal.PostgreSQL.Session.Transaction+ Squeal.PostgreSQL.Type+ Squeal.PostgreSQL.Type.Alias+ Squeal.PostgreSQL.Type.List+ Squeal.PostgreSQL.Type.PG+ Squeal.PostgreSQL.Type.Schema default-language: Haskell2010 ghc-options: -Wall build-depends: aeson >= 1.2.4.0 , base >= 4.11.1.0 && < 5.0+ , binary >= 0.8.6.0 , binary-parser >= 0.5.5 , bytestring >= 0.10.8.2 , bytestring-strict-builder >= 0.4.5 , deepseq >= 1.4.3.0- , generics-sop >= 0.3.2.0 && < 0.5.0.0+ , free-categories >= 0.2.0.0+ , generics-sop >= 0.3.2.0 , mmorph >= 1.1.1 , mtl >= 2.2.2 , network-ip >= 0.3.0.2 , postgresql-binary >= 0.12.1 , postgresql-libpq >= 0.9.4.1+ , profunctors >= 5.3 , records-sop >= 0.1.0.0 , resource-pool >= 0.2.3.2 , scientific >= 0.3.5.3@@ -79,35 +110,83 @@ , uuid-types >= 1.0.3 , vector >= 0.12.0.1 -test-suite squeal-postgresql-doctest+test-suite doctest default-language: Haskell2010 type: exitcode-stdio-1.0 hs-source-dirs: test ghc-options: -Wall- main-is: DocTest.hs+ main-is: Doc.hs build-depends: base >= 4.10.0.0 , doctest >= 0.11.4+ , squeal-postgresql -test-suite squeal-postgresql-specs+test-suite properties default-language: Haskell2010 type: exitcode-stdio-1.0- hs-source-dirs: test/Specs+ hs-source-dirs: test ghc-options: -Wall- main-is: Specs.hs- other-modules: ExceptionHandling+ main-is: Property.hs build-depends: base >= 4.10.0.0- , async >= 2.2.2 , bytestring >= 0.10.8.2+ , hedgehog >= 1.0+ , mtl >= 2.2.2+ , scientific >= 0.3.5.3+ , squeal-postgresql+ , time >= 1.8.0.2+ , with-utf8 >= 1.0++test-suite spec+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ ghc-options: -Wall+ main-is: Spec.hs+ build-depends:+ async >= 2.2.2+ , base >= 4.10.0.0+ , bytestring >= 0.10.8.2 , generics-sop >= 0.3.1.0 , hspec >= 2.4.8+ , mtl >= 2.2.2 , squeal-postgresql , text >= 1.2.2.2- , transformers >= 0.5.2.0 , vector >= 0.12.0.1 -executable squeal-postgresql-example+benchmark gauge+ type: exitcode-stdio-1.0+ hs-source-dirs: bench+ main-is: Gauge.hs+ other-modules:+ Gauge.DBHelpers+ , Gauge.DBSetup+ , Gauge.Queries+ , Gauge.Schema+ default-language: Haskell2010+ ghc-options:+ -O2+ -threaded+ "-with-rtsopts=-N"+ -rtsopts+ -funbox-strict-fields+ build-depends:+ base >= 4.10.0.0+ , bytestring >= 0.10.8.2+ , deepseq >= 1.4.3.0+ , gauge >= 0.2.5+ , generic-random >= 1.2.0.0+ , generics-sop >= 0.3.1.0+ , monad-loops >= 0.4.3+ , mtl >= 2.2.2+ , QuickCheck >= 2.13.2+ , quickcheck-instances >= 0.3.22+ , scientific >= 0.3.5.3+ , squeal-postgresql+ , text >= 1.2.2.2+ , with-utf8 >= 1.0++executable example default-language: Haskell2010 hs-source-dirs: exe ghc-options: -Wall
src/Squeal/PostgreSQL.hs view
@@ -1,6 +1,6 @@ {-| Module: Squeal.PostgreSQL-Description: Squeal export module+Description: export module Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental@@ -44,7 +44,7 @@ type Schema = '[ "users" ::: 'Table (UsersConstraints :=> UsersColumns) , "emails" ::: 'Table (EmailsConstraints :=> EmailsColumns) ]-type Schemas = Public Schema+type DB = Public Schema :} Notice the use of type operators.@@ -54,7 +54,7 @@ operator. `:=>` is used to pair `TableConstraints` with a `ColumnsType`,-yielding a `TableType`, or to pair a `ColumnConstraint` with a `NullityType`,+yielding a `TableType`, or to pair an `Optionality` with a `NullType`, yielding a `ColumnType`. It is intended to connote Haskell's @=>@ operator Next, we'll write `Definition`s to set up and tear down the schema. In@@ -66,7 +66,7 @@ >>> :{ let- setup :: Definition (Public '[]) Schemas+ setup :: Definition (Public '[]) DB setup = createTable #users ( serial `as` #id :*@@ -87,14 +87,14 @@ CREATE TABLE "users" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id")); CREATE TABLE "emails" ("id" serial, "user_id" int NOT NULL, "email" text NULL, CONSTRAINT "pk_emails" PRIMARY KEY ("id"), CONSTRAINT "fk_user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE); -Notice that @setup@ starts with an empty public schema @(Public '[])@ and produces @Schemas@.+Notice that @setup@ starts with an empty public schema @(Public '[])@ and produces @DB@. In our `createTable` commands we included `TableConstraint`s to define primary and foreign keys, making them somewhat complex. Our @teardown@ `Definition` is simpler. >>> :{ let- teardown :: Definition Schemas (Public '[])+ teardown :: Definition DB (Public '[]) teardown = dropTable #emails >>> dropTable #users :} @@ -105,25 +105,27 @@ We'll need a Haskell type for @User@s. We give the type `Generics.SOP.Generic` and `Generics.SOP.HasDatatypeInfo` instances so that we can encode and decode @User@s. ->>> data User = User { userName :: Text, userEmail :: Maybe Text } deriving (Show, GHC.Generic)->>> instance SOP.Generic User->>> instance SOP.HasDatatypeInfo User+>>> :set -XDerivingStrategies -XDeriveAnyClass+>>> :{+data User = User { userName :: Text, userEmail :: Maybe Text }+ deriving stock (Show, GHC.Generic)+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)+:} -Next, we'll write `Manipulation_`s to insert @User@s into our two tables.-A `Manipulation_` like `insertInto`, `update` or `deleteFrom`-has three type parameters, the schemas it refers to, input parameters-and an output row. When+Next, we'll write `Statement`s to insert @User@s into our two tables.+A `Statement` has three type parameters, the schemas it refers to,+input parameters and an output row. When we insert into the users table, we will need a parameter for the @name@ field but not for the @id@ field. Since it's serial, we can use a default value. However, since the emails table refers to the users table, we will need to retrieve the user id that the insert generates and insert it into-the emails table. We can do this in a single `Manipulation_` by using a-`with` statement.+the emails table. We can do this in a single `Statement` by using a+`with` `manipulation`. >>> :{ let- insertUser :: Manipulation_ Schemas User ()- insertUser = with (u `as` #u) e+ insertUser :: Statement DB User ()+ insertUser = manipulation $ with (u `as` #u) e where u = insertInto #users (Values_ (Default `as` #id :* Set (param @1) `as` #name))@@ -136,15 +138,14 @@ >>> printSQL insertUser WITH "u" AS (INSERT INTO "users" ("id", "name") VALUES (DEFAULT, ($1 :: text)) RETURNING "id" AS "id", ($2 :: text) AS "email") INSERT INTO "emails" ("user_id", "email") SELECT "u"."id", "u"."email" FROM "u" AS "u" -Next we write a `Query_` to retrieve users from the database. We're not+Next we write a `Statement` to retrieve users from the database. We're not interested in the ids here, just the usernames and email addresses. We-need to use an `innerJoin` to get the right result. A `Query_` is like a-`Manipulation_` with the same kind of type parameters.+need to use an `innerJoin` to get the right result. >>> :{ let- getUsers :: Query_ Schemas () User- getUsers = select_+ getUsers :: Statement DB () User+ getUsers = query $ select_ (#u ! #name `as` #userName :* #e ! #email `as` #userEmail) ( from (table (#users `as` #u) & innerJoin (table (#emails `as` #e))@@ -176,12 +177,12 @@ >>> :{ let- session :: PQ Schemas Schemas IO ()+ session :: PQ DB DB IO () session = do- _ <- traversePrepared_ insertUser users- usersResult <- runQuery getUsers+ executePrepared_ insertUser users+ usersResult <- execute getUsers usersRows <- getRows usersResult- liftIO $ print (usersRows :: [User])+ liftIO $ print usersRows in withConnection "host=localhost port=5432 dbname=exampledb" $ define setup@@ -190,22 +191,33 @@ :} [User {userName = "Alice", userEmail = Just "alice@gmail.com"},User {userName = "Bob", userEmail = Nothing},User {userName = "Carole", userEmail = Just "carole@hotmail.com"}] -}-module Squeal.PostgreSQL (module X, RenderSQL(..), printSQL) where+module Squeal.PostgreSQL+ ( module X+ , RenderSQL (..)+ , printSQL+ ) where -import Squeal.PostgreSQL.Alias as X-import Squeal.PostgreSQL.Binary as X import Squeal.PostgreSQL.Definition as X+import Squeal.PostgreSQL.Definition.Constraint as X+import Squeal.PostgreSQL.Definition.Function as X+import Squeal.PostgreSQL.Definition.Index as X+import Squeal.PostgreSQL.Definition.Schema as X+import Squeal.PostgreSQL.Definition.Table as X+import Squeal.PostgreSQL.Definition.Type as X+import Squeal.PostgreSQL.Definition.View as X import Squeal.PostgreSQL.Expression as X import Squeal.PostgreSQL.Expression.Aggregate as X-import Squeal.PostgreSQL.Expression.Collection as X+import Squeal.PostgreSQL.Expression.Array as X import Squeal.PostgreSQL.Expression.Comparison as X+import Squeal.PostgreSQL.Expression.Composite as X+import Squeal.PostgreSQL.Expression.Default as X import Squeal.PostgreSQL.Expression.Json as X-import Squeal.PostgreSQL.Expression.Literal as X+import Squeal.PostgreSQL.Expression.Inline as X import Squeal.PostgreSQL.Expression.Logic as X import Squeal.PostgreSQL.Expression.Math as X import Squeal.PostgreSQL.Expression.Null as X import Squeal.PostgreSQL.Expression.Parameter as X-import Squeal.PostgreSQL.Expression.SetOf as X+import Squeal.PostgreSQL.Expression.Range as X import Squeal.PostgreSQL.Expression.Sort as X import Squeal.PostgreSQL.Expression.Subquery as X import Squeal.PostgreSQL.Expression.Text as X@@ -213,13 +225,34 @@ import Squeal.PostgreSQL.Expression.Time as X import Squeal.PostgreSQL.Expression.Type as X import Squeal.PostgreSQL.Expression.Window as X-import Squeal.PostgreSQL.List as X import Squeal.PostgreSQL.Manipulation as X-import Squeal.PostgreSQL.Migration as X-import Squeal.PostgreSQL.PG as X-import Squeal.PostgreSQL.Pool as X-import Squeal.PostgreSQL.PQ as X+import Squeal.PostgreSQL.Manipulation.Delete as X+import Squeal.PostgreSQL.Manipulation.Insert as X+import Squeal.PostgreSQL.Manipulation.Update as X import Squeal.PostgreSQL.Query as X+import Squeal.PostgreSQL.Query.From as X+import Squeal.PostgreSQL.Query.From.Join as X+import Squeal.PostgreSQL.Query.From.Set as X+import Squeal.PostgreSQL.Query.Select as X+import Squeal.PostgreSQL.Query.Table as X+import Squeal.PostgreSQL.Query.Values as X+import Squeal.PostgreSQL.Query.With as X import Squeal.PostgreSQL.Render (RenderSQL(..), printSQL)-import Squeal.PostgreSQL.Schema as X-import Squeal.PostgreSQL.Transaction as X+import Squeal.PostgreSQL.Session as X+import Squeal.PostgreSQL.Session.Connection as X+import Squeal.PostgreSQL.Session.Decode as X+import Squeal.PostgreSQL.Session.Encode as X+import Squeal.PostgreSQL.Session.Exception as X+import Squeal.PostgreSQL.Session.Indexed as X+import Squeal.PostgreSQL.Session.Migration as X+import Squeal.PostgreSQL.Session.Monad as X+import Squeal.PostgreSQL.Session.Oid as X+import Squeal.PostgreSQL.Session.Pool as X+import Squeal.PostgreSQL.Session.Result as X+import Squeal.PostgreSQL.Session.Statement as X+import Squeal.PostgreSQL.Session.Transaction as X+import Squeal.PostgreSQL.Type as X+import Squeal.PostgreSQL.Type.Alias as X+import Squeal.PostgreSQL.Type.List as X+import Squeal.PostgreSQL.Type.PG as X+import Squeal.PostgreSQL.Type.Schema as X
− src/Squeal/PostgreSQL/Alias.hs
@@ -1,249 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Alias-Description: Aliases-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--This module embeds Postgres's alias system in Haskell in-a typesafe fashion. Thanks to GHC's @OverloadedLabels@ extension,-Squeal can reference aliases by prepending with a @#@.--}--{-# LANGUAGE- AllowAmbiguousTypes- , ConstraintKinds- , DeriveAnyClass- , DeriveGeneric- , FlexibleContexts- , FlexibleInstances- , FunctionalDependencies- , GADTs- , LambdaCase- , OverloadedStrings- , QuantifiedConstraints- , RankNTypes- , ScopedTypeVariables- , StandaloneDeriving- , TypeApplications- , TypeFamilyDependencies- , TypeInType- , TypeOperators- , UndecidableInstances- , UndecidableSuperClasses-#-}--module Squeal.PostgreSQL.Alias- ( (:::)- , Alias (..)- , IsLabel (..)- , Aliased (As)- , Aliasable (as)- , renderAliased- , Has- , HasUnique- , HasAll- , HasIn- , QualifiedAlias (..)- , IsQualified (..)- -- * Grouping- , Grouping (..)- , GroupedBy- ) where--import Control.DeepSeq-import Data.ByteString (ByteString)-import Data.String (fromString)-import GHC.OverloadedLabels-import GHC.TypeLits--import qualified Generics.SOP as SOP-import qualified GHC.Generics as GHC--import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Render---- $setup--- >>> import Squeal.PostgreSQL---- | The alias operator `:::` is like a promoted version of `As`,--- a type level pair between an alias and some type.-type (:::) (alias :: Symbol) ty = '(alias,ty)-infixr 6 :::----- | `Grouping` is an auxiliary namespace, created by--- @GROUP BY@ clauses (`Squeal.PostgreSQL.Query.group`), and used--- for typesafe aggregation-data Grouping- = Ungrouped -- ^ no aggregation permitted- | Grouped [(Symbol,Symbol)] -- ^ aggregation required for any column which is not grouped--{- | A `GroupedBy` constraint indicates that a table qualified column is-a member of the auxiliary namespace created by @GROUP BY@ clauses and thus,-may be called in an output `Squeal.PostgreSQL.Expression.Expression` without aggregating.--}-class (KnownSymbol table, KnownSymbol column)- => GroupedBy table column bys where-instance {-# OVERLAPPING #-} (KnownSymbol table, KnownSymbol column)- => GroupedBy table column ('(table,column) ': bys)-instance {-# OVERLAPPABLE #-}- ( KnownSymbol table- , KnownSymbol column- , GroupedBy table column bys- ) => GroupedBy table column (tabcol ': bys)---- | `Alias`es are proxies for a type level string or `Symbol`--- and have an `IsLabel` instance so that with @-XOverloadedLabels@------ >>> :set -XOverloadedLabels--- >>> #foobar :: Alias "foobar"--- Alias-data Alias (alias :: Symbol) = Alias- deriving (Eq,GHC.Generic,Ord,Show,NFData)-instance alias1 ~ alias2 => IsLabel alias1 (Alias alias2) where- fromLabel = Alias-instance aliases ~ '[alias] => IsLabel alias (NP Alias aliases) where- fromLabel = fromLabel SOP.:* Nil--- | >>> printSQL (#jimbob :: Alias "jimbob")--- "jimbob"-instance KnownSymbol alias => RenderSQL (Alias alias) where- renderSQL = doubleQuoted . fromString . symbolVal---- >>> printSQL (#jimbob :* #kandi :: NP Alias '["jimbob", "kandi"])--- "jimbob", "kandi"-instance SOP.All KnownSymbol aliases => RenderSQL (NP Alias aliases) where- renderSQL- = commaSeparated- . SOP.hcollapse- . SOP.hcmap (SOP.Proxy @KnownSymbol) (SOP.K . renderSQL)---- | The `As` operator is used to name an expression. `As` is like a demoted--- version of `:::`.------ >>> Just "hello" `As` #hi :: Aliased Maybe ("hi" ::: String)--- As (Just "hello") Alias-data Aliased expression aliased where- As- :: KnownSymbol alias- => expression ty- -> Alias alias- -> Aliased expression (alias ::: ty)-deriving instance Show (expression ty)- => Show (Aliased expression (alias ::: ty))-deriving instance Eq (expression ty)- => Eq (Aliased expression (alias ::: ty))-deriving instance Ord (expression ty)- => Ord (Aliased expression (alias ::: ty))-instance (alias0 ~ alias1, alias0 ~ alias2, KnownSymbol alias2)- => IsLabel alias0 (Aliased Alias (alias1 ::: alias2)) where- fromLabel = fromLabel @alias2 `As` fromLabel @alias1---- | The `Aliasable` class provides a way to scrap your `Nil`s--- in an `NP` list of `Aliased` expressions.-class KnownSymbol alias => Aliasable alias expression aliased- | aliased -> expression- , aliased -> alias- where as :: expression -> Alias alias -> aliased-instance (KnownSymbol alias, aliased ~ (alias ::: ty)) => Aliasable alias- (expression ty)- (Aliased expression aliased)- where- as = As-instance (KnownSymbol alias, tys ~ '[alias ::: ty]) => Aliasable alias- (expression ty)- (NP (Aliased expression) tys)- where- expression `as` alias = expression `As` alias SOP.:* Nil---- | >>> let renderMaybe = fromString . maybe "Nothing" (const "Just")--- >>> renderAliased renderMaybe (Just (3::Int) `As` #an_int)--- "Just AS \"an_int\""-renderAliased- :: (forall ty. expression ty -> ByteString)- -> Aliased expression aliased- -> ByteString-renderAliased render (expression `As` alias) =- render expression <> " AS " <> renderSQL alias---- | @HasUnique alias fields field@ is a constraint that proves that--- @fields@ is a singleton of @alias ::: field@.-type HasUnique alias fields field = fields ~ '[alias ::: field]---- | @Has alias fields field@ is a constraint that proves that--- @fields@ has a field of @alias ::: field@, inferring @field@--- from @alias@ and @fields@.-class KnownSymbol alias =>- Has (alias :: Symbol) (fields :: [(Symbol,kind)]) (field :: kind)- | alias fields -> field where-instance {-# OVERLAPPING #-} KnownSymbol alias- => Has alias (alias ::: field ': fields) field-instance {-# OVERLAPPABLE #-} (KnownSymbol alias, Has alias fields field)- => Has alias (field' ': fields) field--{-| @HasIn fields (alias ::: field)@ is a constraint that proves that-@fields@ has a field of @alias ::: field@. It is used in @UPDATE@s to-choose which subfields to update.--}-class HasIn fields field where-instance (Has alias fields field) => HasIn fields (alias ::: field) where---- | `HasAll` extends `Has` to take lists of @aliases@ and @fields@ and infer--- a list of @subfields@.-class- ( SOP.All KnownSymbol aliases- ) => HasAll- (aliases :: [Symbol])- (fields :: [(Symbol,kind)])- (subfields :: [(Symbol,kind)])- | aliases fields -> subfields where-instance {-# OVERLAPPING #-} HasAll '[] fields '[]-instance {-# OVERLAPPABLE #-}- (Has alias fields field, HasAll aliases fields subfields)- => HasAll (alias ': aliases) fields (alias ::: field ': subfields)---- | Analagous to `IsLabel`, the constraint--- `IsQualified` defines `!` for a column alias qualified--- by a table alias.-class IsQualified table column expression where- (!) :: Alias table -> Alias column -> expression- infixl 9 !-instance IsQualified table column (Alias table, Alias column) where (!) = (,)--{-| `QualifiedAlias`es enables multi-schema support by allowing a reference-to a `Squeal.PostgreSQL.Schema.Table`, `Squeal.PostgreSQL.Schema.Typedef`-or `Squeal.PostgreSQL.Schema.View` to be qualified by their schemas. By default,-a qualifier of @public@ is provided.-->>> :{-let- alias1 :: QualifiedAlias "sch" "tab"- alias1 = #sch ! #tab- alias2 :: QualifiedAlias "public" "vw"- alias2 = #vw-in printSQL alias1 >> printSQL alias2-:}-"sch"."tab"-"vw"--}-data QualifiedAlias (qualifier :: Symbol) (alias :: Symbol) = QualifiedAlias- deriving (Eq,GHC.Generic,Ord,Show,NFData)-instance (q ~ q', a ~ a') => IsQualified q a (QualifiedAlias q' a') where- _!_ = QualifiedAlias-instance (q' ~ "public", a ~ a') => IsLabel a (QualifiedAlias q' a') where- fromLabel = QualifiedAlias-instance (q0 ~ q1, a0 ~ a1, a1 ~ a2, KnownSymbol a2) =>- IsQualified q0 a0 (Aliased (QualifiedAlias q1) (a1 ::: a2)) where- _!_ = QualifiedAlias `As` Alias-instance (q ~ "public", a0 ~ a1, a1 ~ a2, KnownSymbol a2) =>- IsLabel a0 (Aliased (QualifiedAlias q) (a1 ::: a2)) where- fromLabel = QualifiedAlias `As` Alias--instance (KnownSymbol q, KnownSymbol a)- => RenderSQL (QualifiedAlias q a) where- renderSQL _ =- let- qualifier = renderSQL (Alias @q)- alias = renderSQL (Alias @a)- in- if qualifier == "\"public\"" then alias else qualifier <> "." <> alias
− src/Squeal/PostgreSQL/Binary.hs
@@ -1,757 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Binary-Description: Binary encoding and decoding-Copyright: (c) Eitan Chatav, 2017-Maintainer: eitan@morphism.tech-Stability: experimental--This module provides binary encoding and decoding between Haskell and PostgreSQL types.--Instances are governed by the `SOP.Generic` and `SOP.HasDatatypeInfo` typeclasses, so you absolutely-do not need to define your own instances to decode retrieved rows into Haskell values or-to encode Haskell values into statement parameters.--Let's see some examples. We'll need some imports-->>> import Data.Int (Int16)->>> import Data.Text (Text)->>> import Control.Monad (void)->>> import Control.Monad.IO.Class (liftIO)->>> import Squeal.PostgreSQL--Define a Haskell datatype @Row@ that will serve as both the input and output of a simple-round trip query.-->>> data Row = Row { col1 :: Int16, col2 :: Text, col3 :: Maybe Bool } deriving (Eq, GHC.Generic)->>> instance Generic Row->>> instance HasDatatypeInfo Row->>> :{-let- roundTrip :: Query_ (Public '[]) Row Row- roundTrip = values_ $- parameter @1 int2 `as` #col1 :*- parameter @2 text `as` #col2 :*- parameter @3 bool `as` #col3-:}--So long as we can encode the parameters and then decode the result of the query,-the input and output should be equal.-->>> let input = Row 2 "hi" (Just True)->>> :{-withConnection "host=localhost port=5432 dbname=exampledb" $ do- result <- runQueryParams roundTrip input- Just output <- firstRow result- liftIO . print $ input == output-:}-True--In addition to being able to encode and decode basic Haskell types-like `Int16` and `Data.Text.Text`, Squeal permits you to encode and decode Haskell types to-Postgres array, enumerated and composite types and json. Let's see another example,-this time using the `Vector` type which corresponds to variable length arrays-and homogeneous tuples which correspond to fixed length arrays. We can even-create multi-dimensional fixed length arrays.-->>> :{-data Row = Row- { col1 :: VarArray (Vector Int16)- , col2 :: FixArray (Maybe Int16,Maybe Int16)- , col3 :: FixArray ((Int16,Int16),(Int16,Int16),(Int16,Int16))- } deriving (Eq, GHC.Generic)-:}-->>> instance Generic Row->>> instance HasDatatypeInfo Row--Once again, we define a simple round trip query.-->>> :{-let- roundTrip :: Query_ (Public '[]) Row Row- roundTrip = values_ $- parameter @1 (int2 & vararray) `as` #col1 :*- parameter @2 (int2 & fixarray @'[2]) `as` #col2 :*- parameter @3 (int2 & fixarray @'[3,2]) `as` #col3-:}-->>> :set -XOverloadedLists->>> let input = Row (VarArray [1,2]) (FixArray (Just 1,Nothing)) (FixArray ((1,2),(3,4),(5,6)))->>> :{-withConnection "host=localhost port=5432 dbname=exampledb" $ do- result <- runQueryParams roundTrip input- Just output <- firstRow result- liftIO . print $ input == output-:}-True--Enumerated (enum) types are data types that comprise a static, ordered set of values.-They are equivalent to Haskell algebraic data types whose constructors are nullary.-An example of an enum type might be the days of the week,-or a set of status values for a piece of data.-->>> data Schwarma = Beef | Lamb | Chicken deriving (Eq, Show, GHC.Generic)->>> instance Generic Schwarma->>> instance HasDatatypeInfo Schwarma--A composite type represents the structure of a row or record;-it is essentially just a list of field names and their data types.-->>> data Person = Person {name :: Text, age :: Int32} deriving (Eq, Show, GHC.Generic)->>> instance Generic Person->>> instance HasDatatypeInfo Person->>> instance Aeson.FromJSON Person->>> instance Aeson.ToJSON Person--We can create the equivalent Postgres types directly from their Haskell types.-->>> :{-type Schema =- '[ "schwarma" ::: 'Typedef (PG (Enumerated Schwarma))- , "person" ::: 'Typedef (PG (Composite Person))- ]-:}-->>> :{-let- setup :: Definition (Public '[]) (Public Schema)- setup =- createTypeEnumFrom @Schwarma #schwarma >>>- createTypeCompositeFrom @Person #person-:}--Let's demonstrate how to associate our Haskell types @Schwarma@ and @Person@-with enumerated, composite or json types in Postgres. First create a Haskell-@Row@ type using the `Enumerated`, `Composite` and `Json` newtypes as fields.-->>> :{-data Row = Row- { schwarma :: Enumerated Schwarma- , person1 :: Composite Person- , person2 :: Json Person- } deriving (Eq, GHC.Generic)-:}-->>> instance Generic Row->>> instance HasDatatypeInfo Row->>> :{-let- input = Row- (Enumerated Chicken)- (Composite (Person "Faisal" 24))- (Json (Person "Ahmad" 48))-:}--Once again, define a round trip query.-->>> :{-let- roundTrip :: Query_ (Public Schema) Row Row- roundTrip = values_ $- parameter @1 (typedef #schwarma) `as` #schwarma :*- parameter @2 (typedef #person) `as` #person1 :*- parameter @3 json `as` #person2-:}--Finally, we can drop our type definitions.-->>> :{-let- teardown :: Definition (Public Schema) (Public '[])- teardown = dropType #schwarma >>> dropType #person-:}--Now let's run it.-->>> :{-let- session = do- result <- runQueryParams roundTrip input- Just output <- firstRow result- liftIO . print $ input == output-in- withConnection "host=localhost port=5432 dbname=exampledb" $- define setup- & pqThen session- & pqThen (define teardown)-:}-True--}--{-# LANGUAGE- AllowAmbiguousTypes- , DeriveFoldable- , DeriveFunctor- , DeriveGeneric- , DeriveTraversable- , DefaultSignatures- , FlexibleContexts- , FlexibleInstances- , FunctionalDependencies- , GADTs- , LambdaCase- , OverloadedStrings- , MultiParamTypeClasses- , ScopedTypeVariables- , TypeApplications- , TypeFamilies- , TypeInType- , TypeOperators- , UndecidableInstances- , UndecidableSuperClasses-#-}--module Squeal.PostgreSQL.Binary- ( -- * Encoding- ToParam (..)- , ToParams (..)- , ToNullityParam (..)- , ToField (..)- , ToFixArray (..)- -- * Decoding- , FromValue (..)- , FromRow (..)- , FromField (..)- , FromFixArray (..)- -- * Only- , Only (..)- -- * Oid- , HasOid (..)- , HasAliasedOid (..)- ) where--import BinaryParser-import ByteString.StrictBuilder (builderLength, int32BE, int64BE, word32BE)-import Control.Arrow (left)-import Control.Monad-import Data.Int-import Data.Kind-import Data.Scientific-import Data.Time-import Data.UUID.Types-import Data.Vector (Vector)-import Data.Word-import Generics.SOP-import Generics.SOP.Record-import GHC.TypeLits-import Network.IP.Addr--import qualified Data.Aeson as Aeson-import qualified Data.ByteString.Lazy as Lazy (ByteString)-import qualified Data.ByteString.Lazy as Lazy.ByteString-import qualified Data.ByteString as Strict (ByteString)-import qualified Data.Text.Lazy as Lazy (Text)-import qualified Data.Text as Strict (Text)-import qualified Data.Text as Strict.Text-import qualified Data.Vector as Vector-import qualified GHC.Generics as GHC-import qualified PostgreSQL.Binary.Decoding as Decoding-import qualified PostgreSQL.Binary.Encoding as Encoding--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.PG-import Squeal.PostgreSQL.Schema---- | A `ToParam` constraint gives an encoding of a Haskell `Type` into--- into the binary format of a PostgreSQL `PGType`.-class ToParam (x :: Type) (pg :: PGType) where- -- | >>> :set -XTypeApplications -XDataKinds- -- >>> toParam @Bool @'PGbool False- -- K "\NUL"- --- -- >>> toParam @Int16 @'PGint2 0- -- K "\NUL\NUL"- --- -- >>> toParam @Int32 @'PGint4 0- -- K "\NUL\NUL\NUL\NUL"- --- -- >>> :set -XMultiParamTypeClasses- -- >>> newtype Id = Id { getId :: Int16 } deriving Show- -- >>> instance ToParam Id 'PGint2 where toParam = toParam . getId- -- >>> toParam @Id @'PGint2 (Id 1)- -- K "\NUL\SOH"- toParam :: x -> K Encoding.Encoding pg-instance ToParam Bool 'PGbool where toParam = K . Encoding.bool-instance ToParam Int16 'PGint2 where toParam = K . Encoding.int2_int16-instance ToParam Word16 'PGint2 where toParam = K . Encoding.int2_word16-instance ToParam Int32 'PGint4 where toParam = K . Encoding.int4_int32-instance ToParam Word32 'PGint4 where toParam = K . Encoding.int4_word32-instance ToParam Int64 'PGint8 where toParam = K . Encoding.int8_int64-instance ToParam Word64 'PGint8 where toParam = K . Encoding.int8_word64-instance ToParam Float 'PGfloat4 where toParam = K . Encoding.float4-instance ToParam Double 'PGfloat8 where toParam = K . Encoding.float8-instance ToParam Scientific 'PGnumeric where toParam = K . Encoding.numeric-instance ToParam Money 'PGmoney where toParam = K . Encoding.int8_int64 . cents-instance ToParam UUID 'PGuuid where toParam = K . Encoding.uuid-instance ToParam (NetAddr IP) 'PGinet where toParam = K . Encoding.inet-instance ToParam Char ('PGchar 1) where toParam = K . Encoding.char_utf8-instance ToParam Strict.Text 'PGtext where toParam = K . Encoding.text_strict-instance ToParam Lazy.Text 'PGtext where toParam = K . Encoding.text_lazy-instance ToParam String 'PGtext where- toParam = K . Encoding.text_strict . Strict.Text.pack-instance ToParam Strict.ByteString 'PGbytea where- toParam = K . Encoding.bytea_strict-instance ToParam Lazy.ByteString 'PGbytea where- toParam = K . Encoding.bytea_lazy-instance ToParam Day 'PGdate where toParam = K . Encoding.date-instance ToParam TimeOfDay 'PGtime where toParam = K . Encoding.time_int-instance ToParam (TimeOfDay, TimeZone) 'PGtimetz where- toParam = K . Encoding.timetz_int-instance ToParam LocalTime 'PGtimestamp where- toParam = K . Encoding.timestamp_int-instance ToParam UTCTime 'PGtimestamptz where- toParam = K . Encoding.timestamptz_int-instance ToParam DiffTime 'PGinterval where toParam = K . Encoding.interval_int-instance ToParam Aeson.Value 'PGjson where toParam = K . Encoding.json_ast-instance ToParam Aeson.Value 'PGjsonb where toParam = K . Encoding.jsonb_ast-instance Aeson.ToJSON x => ToParam (Json x) 'PGjson where- toParam = K . Encoding.json_bytes- . Lazy.ByteString.toStrict . Aeson.encode . getJson-instance Aeson.ToJSON x => ToParam (Jsonb x) 'PGjsonb where- toParam = K . Encoding.jsonb_bytes- . Lazy.ByteString.toStrict . Aeson.encode . getJsonb-instance (ToNullityParam x ty, ty ~ nullity pg, HasOid pg)- => ToParam (VarArray [x]) ('PGvararray ty) where- toParam = K- . Encoding.array_foldable (oid @pg) (unK . toNullityParam @x @ty)- . getVarArray-instance (ToParam x pg, HasOid pg)- => ToParam (VarArray (Vector x)) ('PGvararray ('NotNull pg)) where- toParam = K- . Encoding.array_vector (oid @pg) (unK . toParam @x @pg)- . getVarArray-instance (ToParam x pg, HasOid pg)- => ToParam (VarArray (Vector (Maybe x))) ('PGvararray ('Null pg)) where- toParam = K- . Encoding.nullableArray_vector (oid @pg) (unK . toParam @x @pg)- . getVarArray-instance (ToFixArray x dims ty, ty ~ nullity pg, HasOid pg)- => ToParam (FixArray x) ('PGfixarray dims ty) where- toParam = K . Encoding.array (oid @pg)- . unK . unK . toFixArray @x @dims @ty . getFixArray-instance- ( IsEnumType x- , HasDatatypeInfo x- , LabelsPG x ~ labels- ) => ToParam (Enumerated x) ('PGenum labels) where- toParam =- let- gshowConstructor :: NP ConstructorInfo xss -> SOP I xss -> String- gshowConstructor Nil _ = ""- gshowConstructor (constructor :* _) (SOP (Z _)) =- constructorName constructor- gshowConstructor (_ :* constructors) (SOP (S xs)) =- gshowConstructor constructors (SOP xs)- in- K . Encoding.text_strict- . Strict.Text.pack- . gshowConstructor (constructorInfo (datatypeInfo (Proxy @x)))- . from- . getEnumerated-instance- ( SListI fields- , IsRecord x xs- , AllZip ToField xs fields- , All HasAliasedOid fields- ) => ToParam (Composite x) ('PGcomposite fields) where- toParam =- let-- encoders = htrans (Proxy @ToField) toField-- composite- :: All HasAliasedOid row- => NP (K (Maybe Encoding.Encoding)) row- -> K Encoding.Encoding ('PGcomposite row)- composite fields = K $- -- <number of fields: 4 bytes>- -- [for each field]- -- <OID of field's type: sizeof(Oid) bytes>- -- [if value is NULL]- -- <-1: 4 bytes>- -- [else]- -- <length of value: 4 bytes>- -- <value: <length> bytes>- -- [end if]- -- [end for]- int32BE (fromIntegral (lengthSList (Proxy @xs))) <>- let- each- :: HasAliasedOid field- => K (Maybe Encoding.Encoding) field- -> Encoding.Encoding- each (K field :: K (Maybe Encoding.Encoding) field) =- word32BE (aliasedOid @field)- <> case field of- Nothing -> int64BE (-1)- Just value ->- int32BE (fromIntegral (builderLength value))- <> value- in- hcfoldMap (Proxy @HasAliasedOid) each fields-- in- composite . encoders . toRecord . getComposite---- | The object identifier of a `PGType`.------ >>> :set -XTypeApplications--- >>> oid @'PGbool--- 16-class HasOid (ty :: PGType) where oid :: Word32-instance HasOid 'PGbool where oid = 16-instance HasOid 'PGint2 where oid = 21-instance HasOid 'PGint4 where oid = 23-instance HasOid 'PGint8 where oid = 20-instance HasOid 'PGnumeric where oid = 1700-instance HasOid 'PGfloat4 where oid = 700-instance HasOid 'PGfloat8 where oid = 701-instance HasOid ('PGchar n) where oid = 18-instance HasOid ('PGvarchar n) where oid = 1043-instance HasOid 'PGtext where oid = 25-instance HasOid 'PGbytea where oid = 17-instance HasOid 'PGtimestamp where oid = 1114-instance HasOid 'PGtimestamptz where oid = 1184-instance HasOid 'PGdate where oid = 1082-instance HasOid 'PGtime where oid = 1083-instance HasOid 'PGtimetz where oid = 1266-instance HasOid 'PGinterval where oid = 1186-instance HasOid 'PGuuid where oid = 2950-instance HasOid 'PGinet where oid = 869-instance HasOid 'PGjson where oid = 114-instance HasOid 'PGjsonb where oid = 3802---- | Lifts a `HasOid` constraint to a field.-class HasAliasedOid (field :: (Symbol, NullityType)) where- aliasedOid :: Word32-instance HasOid ty => HasAliasedOid (alias ::: nullity ty) where- aliasedOid = oid @ty---- | A `ToNullityParam` constraint gives an encoding of a Haskell `Type` into--- into the binary format of a PostgreSQL `NullityType`.-class ToNullityParam (x :: Type) (ty :: NullityType) where- toNullityParam :: x -> K (Maybe Encoding.Encoding) ty-instance ToParam x pg => ToNullityParam x ('NotNull pg) where- toNullityParam = K . Just . unK . toParam @x @pg-instance ToParam x pg => ToNullityParam (Maybe x) ('Null pg) where- toNullityParam = K . fmap (unK . toParam @x @pg)---- | A `ToField` constraint lifts the `ToParam` parser--- to an encoding of a @(Symbol, Type)@ to a @(Symbol, NullityType)@,--- encoding `Null`s to `Maybe`s. You should not define instances for--- `FromField`, just use the provided instances.-class ToField (x :: (Symbol, Type)) (field :: (Symbol, NullityType)) where- toField :: P x -> K (Maybe Encoding.Encoding) field-instance ToNullityParam x ty => ToField (alias ::: x) (alias ::: ty) where- toField (P x) = K . unK $ toNullityParam @x @ty x---- | A `ToFixArray` constraint gives an encoding of a Haskell `Type`--- into the binary format of a PostgreSQL fixed-length array.--- You should not define instances for--- `ToFixArray`, just use the provided instances.-class ToFixArray (x :: Type) (dims :: [Nat]) (array :: NullityType) where- toFixArray :: x -> K (K Encoding.Array dims) array-instance ToNullityParam x ty => ToFixArray x '[] ty where- toFixArray = K . K . maybe Encoding.nullArray Encoding.encodingArray . unK- . toNullityParam @x @ty-instance- ( IsProductType product xs- , Length xs ~ dim- , All ((~) x) xs- , ToFixArray x dims ty )- => ToFixArray product (dim ': dims) ty where- toFixArray = K . K . Encoding.dimensionArray foldlN- (unK . unK . toFixArray @x @dims @ty) . unZ . unSOP . from---- | A `ToParams` constraint generically sequences the encodings of `Type`s--- of the fields of a tuple or record to a row of `ColumnType`s. You should--- not define instances of `ToParams`. Instead define `SOP.Generic` instances--- which in turn provide `ToParams` instances.-class SListI tys => ToParams (x :: Type) (tys :: [NullityType]) where- -- | >>> type Params = '[ 'NotNull 'PGbool, 'Null 'PGint2]- -- >>> toParams @(Bool, Maybe Int16) @'[ 'NotNull 'PGbool, 'Null 'PGint2] (False, Just 0)- -- K (Just "\NUL") :* K (Just "\NUL\NUL") :* Nil- --- -- >>> :set -XDeriveGeneric- -- >>> data Tuple = Tuple { p1 :: Bool, p2 :: Maybe Int16} deriving GHC.Generic- -- >>> instance Generic Tuple- -- >>> toParams @Tuple @Params (Tuple False (Just 0))- -- K (Just "\NUL") :* K (Just "\NUL\NUL") :* Nil- toParams :: x -> NP (K (Maybe Encoding.Encoding)) tys-instance (SListI tys, IsProductType x xs, AllZip ToNullityParam xs tys)- => ToParams x tys where- toParams- = htrans (Proxy @ToNullityParam) (toNullityParam . unI)- . unZ . unSOP . from---- | A `FromValue` constraint gives a parser from the binary format of--- a PostgreSQL `PGType` into a Haskell `Type`.-class FromValue (pg :: PGType) (y :: Type) where- -- | >>> newtype Id = Id { getId :: Int16 } deriving Show- -- >>> instance FromValue 'PGint2 Id where fromValue = Id <$> fromValue @'PGint2- fromValue :: Decoding.Value y-instance FromValue 'PGbool Bool where fromValue = Decoding.bool-instance FromValue 'PGint2 Int16 where fromValue = Decoding.int-instance FromValue 'PGint4 Int32 where fromValue = Decoding.int-instance FromValue 'PGint8 Int64 where fromValue = Decoding.int-instance FromValue 'PGfloat4 Float where fromValue = Decoding.float4-instance FromValue 'PGfloat8 Double where fromValue = Decoding.float8-instance FromValue 'PGnumeric Scientific where fromValue = Decoding.numeric-instance FromValue 'PGmoney Money where fromValue = Money <$> Decoding.int-instance FromValue 'PGuuid UUID where fromValue = Decoding.uuid-instance FromValue 'PGinet (NetAddr IP) where fromValue = Decoding.inet-instance FromValue ('PGchar 1) Char where fromValue = Decoding.char-instance FromValue 'PGtext Strict.Text where fromValue = Decoding.text_strict-instance FromValue 'PGtext Lazy.Text where fromValue = Decoding.text_lazy-instance FromValue 'PGtext String where- fromValue = Strict.Text.unpack <$> Decoding.text_strict-instance FromValue 'PGbytea Strict.ByteString where- fromValue = Decoding.bytea_strict-instance FromValue 'PGbytea Lazy.ByteString where- fromValue = Decoding.bytea_lazy-instance FromValue 'PGdate Day where fromValue = Decoding.date-instance FromValue 'PGtime TimeOfDay where fromValue = Decoding.time_int-instance FromValue 'PGtimetz (TimeOfDay, TimeZone) where- fromValue = Decoding.timetz_int-instance FromValue 'PGtimestamp LocalTime where- fromValue = Decoding.timestamp_int-instance FromValue 'PGtimestamptz UTCTime where- fromValue = Decoding.timestamptz_int-instance FromValue 'PGinterval DiffTime where- fromValue = Decoding.interval_int-instance FromValue 'PGjson Aeson.Value where fromValue = Decoding.json_ast-instance FromValue 'PGjsonb Aeson.Value where fromValue = Decoding.jsonb_ast-instance Aeson.FromJSON x => FromValue 'PGjson (Json x) where- fromValue = Json <$>- Decoding.json_bytes (left Strict.Text.pack . Aeson.eitherDecodeStrict)-instance Aeson.FromJSON x => FromValue 'PGjsonb (Jsonb x) where- fromValue = Jsonb <$>- Decoding.jsonb_bytes (left Strict.Text.pack . Aeson.eitherDecodeStrict)-instance FromValue pg y- => FromValue ('PGvararray ('NotNull pg)) (VarArray (Vector y)) where- fromValue =- let- rep n x = VarArray <$> Vector.replicateM n x- in- Decoding.array $ Decoding.dimensionArray rep- (fromFixArray @'[] @('NotNull pg))-instance FromValue pg y- => FromValue ('PGvararray ('Null pg)) (VarArray (Vector (Maybe y))) where- fromValue =- let- rep n x = VarArray <$> Vector.replicateM n x- in- Decoding.array $ Decoding.dimensionArray rep- (fromFixArray @'[] @('Null pg))-instance FromValue pg y- => FromValue ('PGvararray ('NotNull pg)) (VarArray [y]) where- fromValue =- let- rep n x = VarArray <$> replicateM n x- in- Decoding.array $ Decoding.dimensionArray rep- (fromFixArray @'[] @('NotNull pg))-instance FromValue pg y- => FromValue ('PGvararray ('Null pg)) (VarArray [Maybe y]) where- fromValue =- let- rep n x = VarArray <$> replicateM n x- in- Decoding.array $ Decoding.dimensionArray rep- (fromFixArray @'[] @('Null pg))-instance FromFixArray dims ty y- => FromValue ('PGfixarray dims ty) (FixArray y) where- fromValue = FixArray <$> Decoding.array (fromFixArray @dims @ty @y)-instance- ( IsEnumType y- , HasDatatypeInfo y- , LabelsPG y ~ labels- ) => FromValue ('PGenum labels) (Enumerated y) where- fromValue =- let- greadConstructor- :: All ((~) '[]) xss- => NP ConstructorInfo xss- -> String- -> Maybe (SOP I xss)- greadConstructor Nil _ = Nothing- greadConstructor (constructor :* constructors) name =- if name == constructorName constructor- then Just (SOP (Z Nil))- else SOP . S . unSOP <$> greadConstructor constructors name- in- fmap Enumerated- . Decoding.enum- $ fmap to- . greadConstructor (constructorInfo (datatypeInfo (Proxy @y)))- . Strict.Text.unpack-instance- ( FromRow fields y- ) => FromValue ('PGcomposite fields) (Composite y) where- fromValue =- let- -- <number of fields: 4 bytes>- -- [for each field]- -- <OID of field's type: sizeof(Oid) bytes>- -- [if value is NULL]- -- <-1: 4 bytes>- -- [else]- -- <length of value: 4 bytes>- -- <value: <length> bytes>- -- [end if]- -- [end for]- composite = Decoding.valueParser $ do- unitOfSize 4- hsequence' $ hpure $ Comp $ do- unitOfSize 4- len <- sized 4 Decoding.int- if len == -1- then return (K Nothing)- else K . Just <$> bytesOfSize len- in- fmap Composite (Decoding.fn (fromRow @fields <=< composite))---- | A `FromField` constraint lifts the `FromValue` parser--- to a decoding of a @(Symbol, NullityType)@ to a `Type`,--- decoding `Null`s to `Maybe`s. You should not define instances for--- `FromField`, just use the provided instances.-class FromField (pg :: (Symbol, NullityType)) (y :: (Symbol, Type)) where- fromField- :: K (Maybe Strict.ByteString) pg- -> (Either Strict.Text :.: P) y-instance FromValue pg y- => FromField (column ::: ('NotNull pg)) (column ::: y) where- fromField = Comp . \case- K Nothing -> Left "fromField: saw NULL when expecting NOT NULL"- K (Just bytestring) -> P <$>- Decoding.valueParser (fromValue @pg) bytestring-instance FromValue pg y- => FromField (column ::: 'Null pg) (column ::: Maybe y) where- fromField = Comp . \case- K Nothing -> Right $ P Nothing- K (Just bytestring) -> P . Just <$>- Decoding.valueParser (fromValue @pg) bytestring---- | A `FromFixArray` constraint gives a decoding to a Haskell `Type`--- from the binary format of a PostgreSQL fixed-length array.--- You should not define instances for--- `FromFixArray`, just use the provided instances.-class FromFixArray (dims :: [Nat]) (ty :: NullityType) (y :: Type) where- fromFixArray :: Decoding.Array y-instance FromValue pg y => FromFixArray '[] ('NotNull pg) y where- fromFixArray = Decoding.valueArray (fromValue @pg @y)-instance FromValue pg y => FromFixArray '[] ('Null pg) (Maybe y) where- fromFixArray = Decoding.nullableValueArray (fromValue @pg @y)-instance- ( IsProductType product ys- , Length ys ~ dim- , All ((~) y) ys- , FromFixArray dims ty y )- => FromFixArray (dim ': dims) ty product where- fromFixArray =- let- rep _ = fmap (to . SOP . Z) . replicateMN- in- Decoding.dimensionArray rep (fromFixArray @dims @ty @y)---- | A `FromRow` constraint generically sequences the parsings of the columns--- of a `RowType` into the fields of a record `Type` provided they have--- the same field names. You should not define instances of `FromRow`.--- Instead define `SOP.Generic` and `SOP.HasDatatypeInfo` instances which in turn--- provide `FromRow` instances.-class SListI result => FromRow (result :: RowType) y where- -- | >>> :set -XOverloadedStrings- -- >>> import Data.Text- -- >>> newtype UserId = UserId { getUserId :: Int16 } deriving Show- -- >>> instance FromValue 'PGint2 UserId where fromValue = UserId <$> fromValue @'PGint2- -- >>> data UserRow = UserRow { userId :: UserId, userName :: Maybe Text } deriving (Show, GHC.Generic)- -- >>> instance Generic UserRow- -- >>> instance HasDatatypeInfo UserRow- -- >>> type User = '["userId" ::: 'NotNull 'PGint2, "userName" ::: 'Null 'PGtext]- -- >>> fromRow @User @UserRow (K (Just "\NUL\SOH") :* K (Just "bloodninja") :* Nil)- -- Right (UserRow {userId = UserId {getUserId = 1}, userName = Just "bloodninja"})- fromRow :: NP (K (Maybe Strict.ByteString)) result -> Either Strict.Text y-instance- ( SListI result- , IsRecord y ys- , AllZip FromField result ys- ) => FromRow result y where- fromRow- = fmap fromRecord- . hsequence'- . htrans (Proxy @FromField) fromField---------------------------------------------------------- P records---------------------------------------------------------- instance (FromField (col ::: pg) (col ::: hask))--- => FromRow '[col ::: pg] (P (col ::: hask)) where--- fromRow (pg :* Nil) = (unComp . fromField) pg--- instance--- ( row ~ Join row1 row2--- , FromRow row1 hask1--- , FromRow row2 hask2--- , SListI row--- ) => FromRow row (hask1, hask2) where--- fromRow row = case disjoin @row1 @row2 row of--- (row1, row2) -> (,) <$> fromRow row1 <*> fromRow row2--- instance--- ( row ~ Join row1 row23--- , FromRow row1 hask1--- , FromRow row23 (hask2, hask3)--- , SListI row--- ) => FromRow row (hask1, hask2, hask3) where--- fromRow row = case disjoin @row1 @row23 row of--- (row1, row23) -> do--- hask1 <- fromRow row1--- (hask2, hask3) <- fromRow row23--- return (hask1, hask2, hask3)--- instance--- ( row ~ Join row1 row234--- , FromRow row1 hask1--- , FromRow row234 (hask2, hask3, hask4)--- , SListI row--- ) => FromRow row (hask1, hask2, hask3, hask4) where--- fromRow row = case disjoin @row1 @row234 row of--- (row1, row234) -> do--- hask1 <- fromRow row1--- (hask2, hask3, hask4) <- fromRow row234--- return (hask1, hask2, hask3, hask4)--- instance--- ( row ~ Join row1 row2345--- , FromRow row1 hask1--- , FromRow row2345 (hask2, hask3, hask4, hask5)--- , SListI row--- ) => FromRow row (hask1, hask2, hask3, hask4, hask5) where--- fromRow row = case disjoin @row1 @row2345 row of--- (row1, row2345) -> do--- hask1 <- fromRow row1--- (hask2, hask3, hask4, hask5) <- fromRow row2345--- return (hask1, hask2, hask3, hask4, hask5)---- | `Only` is a 1-tuple type, useful for encoding a single parameter with--- `toParams` or decoding a single value with `fromRow`.------ >>> import Data.Text--- >>> toParams @(Only (Maybe Text)) @'[ 'Null 'PGtext] (Only (Just "foo"))--- K (Just "foo") :* Nil------ >>> fromRow @'["fromOnly" ::: 'Null 'PGtext] @(Only (Maybe Text)) (K (Just "bar") :* Nil)--- Right (Only {fromOnly = Just "bar"})-newtype Only x = Only { fromOnly :: x }- deriving (Functor,Foldable,Traversable,Eq,Ord,Read,Show,GHC.Generic)-instance Generic (Only x)-instance HasDatatypeInfo (Only x)--foldlN- :: All ((~) x) xs- => (z -> x -> z) -> z -> NP I xs -> z-foldlN f z = \case- Nil -> z- I x :* xs -> let z' = f z x in seq z' $ foldlN f z' xs--replicateMN- :: forall x xs m. (All ((~) x) xs, Monad m, SListI xs)- => m x -> m (NP I xs)-replicateMN mx = hsequence' $- hcpure (Proxy :: Proxy ((~) x)) (Comp (I <$> mx))
src/Squeal/PostgreSQL/Definition.hs view
@@ -1,1110 +1,87 @@ {-| Module: Squeal.PostgreSQL.Definition-Description: Squeal data definition language-Copyright: (c) Eitan Chatav, 2017-Maintainer: eitan@morphism.tech-Stability: experimental--Squeal data definition language.--}--{-# LANGUAGE- AllowAmbiguousTypes- , ConstraintKinds- , DeriveGeneric- , FlexibleContexts- , FlexibleInstances- , GADTs- , GeneralizedNewtypeDeriving- , LambdaCase- , MultiParamTypeClasses- , OverloadedStrings- , RankNTypes- , ScopedTypeVariables- , TypeApplications- , TypeInType- , TypeOperators- , UndecidableSuperClasses-#-}--module Squeal.PostgreSQL.Definition- ( -- * Definition- Definition (..)- , (>>>)- , manipDefinition- -- * Tables- -- ** Create- , createSchema- , createSchemaIfNotExists- , createTable- , createTableIfNotExists- , createView- , createTypeEnum- , createTypeEnumFrom- , createTypeComposite- , createTypeCompositeFrom- , FieldTyped (..)- , createDomain- , TableConstraintExpression (..)- , check- , unique- , primaryKey- , foreignKey- , ForeignKeyed- , OnDeleteClause (..)- , OnUpdateClause (..)- -- ** Drop- , dropSchema- , dropTable- , dropView- , dropType- -- ** Alter- , alterTable- , alterTableRename- , AlterTable (..)- , addConstraint- , dropConstraint- , AddColumn (..)- , dropColumn- , renameColumn- , alterColumn- , AlterColumn (..)- , setDefault- , dropDefault- , setNotNull- , dropNotNull- , alterType- -- * Columns- , ColumnTypeExpression (..)- , nullable- , notNullable- , default_- , serial2- , smallserial- , serial4- , serial- , serial8- , bigserial- ) where--import Control.Category-import Control.DeepSeq-import Data.ByteString-import Data.Monoid-import GHC.TypeLits-import Prelude hiding ((.), id)--import qualified Generics.SOP as SOP-import qualified GHC.Generics as GHC--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Expression.Logic-import Squeal.PostgreSQL.Expression.Type-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.PG-import Squeal.PostgreSQL.Query-import Squeal.PostgreSQL.Manipulation-import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema---- $setup--- >>> import Squeal.PostgreSQL--{------------------------------------------statements------------------------------------------}---- | A `Definition` is a statement that changes the schemas of the--- database, like a `createTable`, `dropTable`, or `alterTable` command.--- `Definition`s may be composed using the `>>>` operator.-newtype Definition- (schemas0 :: SchemasType)- (schemas1 :: SchemasType)- = UnsafeDefinition { renderDefinition :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)--instance RenderSQL (Definition schemas0 schemas1) where- renderSQL = renderDefinition--instance Category Definition where- id = UnsafeDefinition ";"- ddl1 . ddl0 = UnsafeDefinition $- renderSQL ddl0 <> "\n" <> renderSQL ddl1---- | A `Manipulation` without input or output can be run as a statement--- along with other `Definition`s, by embedding it using `manipDefinition`.-manipDefinition- :: Manipulation '[] schemas '[] '[]- -- ^ no input or output- -> Definition schemas schemas-manipDefinition = UnsafeDefinition . (<> ";") . renderSQL--{------------------------------------------CREATE statements------------------------------------------}--{- |-`createSchema` enters a new schema into the current database.-The schema name must be distinct from the name of any existing schema-in the current database.--A schema is essentially a namespace: it contains named objects-(tables, data types, functions, and operators) whose names-can duplicate those of other objects existing in other schemas.-Named objects are accessed by `QualifiedAlias`es with the schema-name as a prefix.--}-createSchema- :: KnownSymbol sch- => Alias sch- -> Definition schemas (Create sch '[] schemas)-createSchema sch = UnsafeDefinition $- "CREATE" <+> "SCHEMA" <+> renderSQL sch <> ";"--{- | Idempotent version of `createSchema`. -}-createSchemaIfNotExists- :: (KnownSymbol sch, Has sch schemas schema)- => Alias sch- -> Definition schemas schemas-createSchemaIfNotExists sch = UnsafeDefinition $- "CREATE" <+> "SCHEMA" <+> "IF" <+> "NOT" <+> "EXISTS"- <+> renderSQL sch <> ";"--{- | `createTable` adds a table to the schema.-->>> :set -XOverloadedLabels->>> :{-type Table = '[] :=>- '[ "a" ::: 'NoDef :=> 'Null 'PGint4- , "b" ::: 'NoDef :=> 'Null 'PGfloat4 ]-:}-->>> :{-let- setup :: Definition (Public '[]) (Public '["tab" ::: 'Table Table])- setup = createTable #tab- (nullable int `as` #a :* nullable real `as` #b) Nil-in printSQL setup-:}-CREATE TABLE "tab" ("a" int NULL, "b" real NULL);--}-createTable- :: ( KnownSymbol sch- , KnownSymbol tab- , columns ~ (col ': cols)- , SOP.SListI columns- , SOP.SListI constraints- , Has sch schemas0 schema0- , schemas1 ~ Alter sch (Create tab ('Table (constraints :=> columns)) schema0) schemas0 )- => QualifiedAlias sch tab -- ^ the name of the table to add- -> NP (Aliased (ColumnTypeExpression schemas0)) columns- -- ^ the names and datatype of each column- -> NP (Aliased (TableConstraintExpression sch tab schemas1)) constraints- -- ^ constraints that must hold for the table- -> Definition schemas0 schemas1-createTable tab columns constraints = UnsafeDefinition $- "CREATE TABLE" <+> renderCreation tab columns constraints--{-| `createTableIfNotExists` creates a table if it doesn't exist, but does not add it to the schema.-Instead, the schema already has the table so if the table did not yet exist, the schema was wrong.-`createTableIfNotExists` fixes this. Interestingly, this property makes it an idempotent in-the `Category` of `Definition`s.-->>> :set -XOverloadedLabels -XTypeApplications->>> :{-type Table = '[] :=>- '[ "a" ::: 'NoDef :=> 'Null 'PGint4- , "b" ::: 'NoDef :=> 'Null 'PGfloat4 ]-:}-->>> type Schemas = Public '["tab" ::: 'Table Table]-->>> :{-let- setup :: Definition Schemas Schemas- setup = createTableIfNotExists #tab- (nullable int `as` #a :* nullable real `as` #b) Nil-in printSQL setup-:}-CREATE TABLE IF NOT EXISTS "tab" ("a" int NULL, "b" real NULL);--}-createTableIfNotExists- :: ( Has sch schemas schema- , Has tab schema ('Table (constraints :=> columns))- , SOP.SListI columns- , SOP.SListI constraints )- => QualifiedAlias sch tab -- ^ the name of the table to add- -> NP (Aliased (ColumnTypeExpression schemas)) columns- -- ^ the names and datatype of each column- -> NP (Aliased (TableConstraintExpression sch tab schemas)) constraints- -- ^ constraints that must hold for the table- -> Definition schemas schemas-createTableIfNotExists tab columns constraints = UnsafeDefinition $- "CREATE TABLE IF NOT EXISTS"- <+> renderCreation tab columns constraints---- helper function for `createTable` and `createTableIfNotExists`-renderCreation- :: ( KnownSymbol sch- , KnownSymbol tab- , SOP.SListI columns- , SOP.SListI constraints )- => QualifiedAlias sch tab -- ^ the name of the table to add- -> NP (Aliased (ColumnTypeExpression schemas0)) columns- -- ^ the names and datatype of each column- -> NP (Aliased (TableConstraintExpression sch tab schemas1)) constraints- -- ^ constraints that must hold for the table- -> ByteString-renderCreation tab columns constraints = renderSQL tab- <+> parenthesized- ( renderCommaSeparated renderColumnDef columns- <> ( case constraints of- Nil -> ""- _ -> ", " <>- renderCommaSeparated renderConstraint constraints ) )- <> ";"- where- renderColumnDef :: Aliased (ColumnTypeExpression schemas) x -> ByteString- renderColumnDef (ty `As` column) =- renderSQL column <+> renderColumnTypeExpression ty- renderConstraint- :: Aliased (TableConstraintExpression sch tab schemas) constraint- -> ByteString- renderConstraint (constraint `As` alias) =- "CONSTRAINT" <+> renderSQL alias <+> renderSQL constraint---- | Data types are a way to limit the kind of data that can be stored in a--- table. For many applications, however, the constraint they provide is--- too coarse. For example, a column containing a product price should--- probably only accept positive values. But there is no standard data type--- that accepts only positive numbers. Another issue is that you might want--- to constrain column data with respect to other columns or rows.--- For example, in a table containing product information,--- there should be only one row for each product number.--- `TableConstraint`s give you as much control over the data in your tables--- as you wish. If a user attempts to store data in a column that would--- violate a constraint, an error is raised. This applies--- even if the value came from the default value definition.-newtype TableConstraintExpression- (sch :: Symbol)- (tab :: Symbol)- (schemas :: SchemasType)- (constraint :: TableConstraint)- = UnsafeTableConstraintExpression- { renderTableConstraintExpression :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL- (TableConstraintExpression sch tab schemas constraint) where- renderSQL = renderTableConstraintExpression--{-| A `check` constraint is the most generic `TableConstraint` type.-It allows you to specify that the value in a certain column must satisfy-a Boolean (truth-value) expression.-->>> :{-type Schema = '[- "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[- "a" ::: 'NoDef :=> 'NotNull 'PGint4,- "b" ::: 'NoDef :=> 'NotNull 'PGint4- ])]-:}-->>> :{-let- definition :: Definition (Public '[]) (Public Schema)- definition = createTable #tab- ( (int & notNullable) `as` #a :*- (int & notNullable) `as` #b )- ( check (#a :* #b) (#a .> #b) `as` #inequality )-:}-->>> printSQL definition-CREATE TABLE "tab" ("a" int NOT NULL, "b" int NOT NULL, CONSTRAINT "inequality" CHECK (("a" > "b")));--}-check- :: ( Has sch schemas schema- , Has tab schema ('Table table)- , HasAll aliases (TableToRow table) subcolumns )- => NP Alias aliases- -- ^ specify the subcolumns which are getting checked- -> (forall t. Condition '[] '[] 'Ungrouped schemas '[] '[t ::: subcolumns])- -- ^ a closed `Condition` on those subcolumns- -> TableConstraintExpression sch tab schemas ('Check aliases)-check _cols condition = UnsafeTableConstraintExpression $- "CHECK" <+> parenthesized (renderSQL condition)--{-| A `unique` constraint ensure that the data contained in a column,-or a group of columns, is unique among all the rows in the table.-->>> :{-type Schema = '[- "tab" ::: 'Table( '[ "uq_a_b" ::: 'Unique '["a","b"]] :=> '[- "a" ::: 'NoDef :=> 'Null 'PGint4,- "b" ::: 'NoDef :=> 'Null 'PGint4- ])]-:}-->>> :{-let- definition :: Definition (Public '[]) (Public Schema)- definition = createTable #tab- ( (int & nullable) `as` #a :*- (int & nullable) `as` #b )- ( unique (#a :* #b) `as` #uq_a_b )-:}-->>> printSQL definition-CREATE TABLE "tab" ("a" int NULL, "b" int NULL, CONSTRAINT "uq_a_b" UNIQUE ("a", "b"));--}-unique- :: ( Has sch schemas schema- , Has tab schema('Table table)- , HasAll aliases (TableToRow table) subcolumns )- => NP Alias aliases- -- ^ specify subcolumns which together are unique for each row- -> TableConstraintExpression sch tab schemas ('Unique aliases)-unique columns = UnsafeTableConstraintExpression $- "UNIQUE" <+> parenthesized (renderSQL columns)--{-| A `primaryKey` constraint indicates that a column, or group of columns,-can be used as a unique identifier for rows in the table.-This requires that the values be both unique and not null.-->>> :{-type Schema = '[- "tab" ::: 'Table ('[ "pk_id" ::: 'PrimaryKey '["id"]] :=> '[- "id" ::: 'Def :=> 'NotNull 'PGint4,- "name" ::: 'NoDef :=> 'NotNull 'PGtext- ])]-:}-->>> :{-let- definition :: Definition (Public '[]) (Public Schema)- definition = createTable #tab- ( serial `as` #id :*- (text & notNullable) `as` #name )- ( primaryKey #id `as` #pk_id )-:}-->>> printSQL definition-CREATE TABLE "tab" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_id" PRIMARY KEY ("id"));--}-primaryKey- :: ( Has sch schemas schema- , Has tab schema ('Table table)- , HasAll aliases (TableToColumns table) subcolumns- , AllNotNull subcolumns )- => NP Alias aliases- -- ^ specify the subcolumns which together form a primary key.- -> TableConstraintExpression sch tab schemas ('PrimaryKey aliases)-primaryKey columns = UnsafeTableConstraintExpression $- "PRIMARY KEY" <+> parenthesized (renderSQL columns)--{-| A `foreignKey` specifies that the values in a column-(or a group of columns) must match the values appearing in some row of-another table. We say this maintains the referential integrity-between two related tables.-->>> :{-type Schema =- '[ "users" ::: 'Table (- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "name" ::: 'NoDef :=> 'NotNull 'PGtext- ])- , "emails" ::: 'Table (- '[ "pk_emails" ::: 'PrimaryKey '["id"]- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]- ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4- , "email" ::: 'NoDef :=> 'Null 'PGtext- ])- ]-:}-->>> :{-let- setup :: Definition (Public '[]) (Public Schema)- setup =- createTable #users- ( serial `as` #id :*- (text & notNullable) `as` #name )- ( primaryKey #id `as` #pk_users ) >>>- createTable #emails- ( serial `as` #id :*- (int & notNullable) `as` #user_id :*- (text & nullable) `as` #email )- ( primaryKey #id `as` #pk_emails :*- foreignKey #user_id #users #id- OnDeleteCascade OnUpdateCascade `as` #fk_user_id )-in printSQL setup-:}-CREATE TABLE "users" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"));-CREATE TABLE "emails" ("id" serial, "user_id" int NOT NULL, "email" text NULL, CONSTRAINT "pk_emails" PRIMARY KEY ("id"), CONSTRAINT "fk_user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE);--A `foreignKey` can even be a table self-reference.-->>> :{-type Schema =- '[ "employees" ::: 'Table (- '[ "employees_pk" ::: 'PrimaryKey '["id"]- , "employees_employer_fk" ::: 'ForeignKey '["employer_id"] "employees" '["id"]- ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "name" ::: 'NoDef :=> 'NotNull 'PGtext- , "employer_id" ::: 'NoDef :=> 'Null 'PGint4- ])- ]-:}-->>> :{-let- setup :: Definition (Public '[]) (Public Schema)- setup =- createTable #employees- ( serial `as` #id :*- (text & notNullable) `as` #name :*- (integer & nullable) `as` #employer_id )- ( primaryKey #id `as` #employees_pk :*- foreignKey #employer_id #employees #id- OnDeleteCascade OnUpdateCascade `as` #employees_employer_fk )-in printSQL setup-:}-CREATE TABLE "employees" ("id" serial, "name" text NOT NULL, "employer_id" integer NULL, CONSTRAINT "employees_pk" PRIMARY KEY ("id"), CONSTRAINT "employees_employer_fk" FOREIGN KEY ("employer_id") REFERENCES "employees" ("id") ON DELETE CASCADE ON UPDATE CASCADE);--}-foreignKey- :: (ForeignKeyed schemas sch schema child parent- table reftable- columns refcolumns- constraints cols- reftys tys )- => NP Alias columns- -- ^ column or columns in the table- -> Alias parent- -- ^ reference table- -> NP Alias refcolumns- -- ^ reference column or columns in the reference table- -> OnDeleteClause- -- ^ what to do when reference is deleted- -> OnUpdateClause- -- ^ what to do when reference is updated- -> TableConstraintExpression sch child schemas- ('ForeignKey columns parent refcolumns)-foreignKey keys parent refs ondel onupd = UnsafeTableConstraintExpression $- "FOREIGN KEY" <+> parenthesized (renderSQL keys)- <+> "REFERENCES" <+> renderSQL parent- <+> parenthesized (renderSQL refs)- <+> renderSQL ondel- <+> renderSQL onupd---- | A constraint synonym between types involved in a foreign key constraint.-type ForeignKeyed schemas- sch- schema- child parent- table reftable- columns refcolumns- constraints cols- reftys tys =- ( Has sch schemas schema- , Has child schema ('Table table)- , Has parent schema ('Table reftable)- , HasAll columns (TableToColumns table) tys- , reftable ~ (constraints :=> cols)- , HasAll refcolumns cols reftys- , SOP.AllZip SamePGType tys reftys- , Uniquely refcolumns constraints )---- | `OnDeleteClause` indicates what to do with rows that reference a deleted row.-data OnDeleteClause- = OnDeleteNoAction- -- ^ if any referencing rows still exist when the constraint is checked,- -- an error is raised- | OnDeleteRestrict -- ^ prevents deletion of a referenced row- | OnDeleteCascade- -- ^ specifies that when a referenced row is deleted,- -- row(s) referencing it should be automatically deleted as well- deriving (GHC.Generic,Show,Eq,Ord)-instance NFData OnDeleteClause--- | Render `OnDeleteClause`.-instance RenderSQL OnDeleteClause where- renderSQL = \case- OnDeleteNoAction -> "ON DELETE NO ACTION"- OnDeleteRestrict -> "ON DELETE RESTRICT"- OnDeleteCascade -> "ON DELETE CASCADE"---- | Analagous to `OnDeleteClause` there is also `OnUpdateClause` which is invoked--- when a referenced column is changed (updated).-data OnUpdateClause- = OnUpdateNoAction- -- ^ if any referencing rows has not changed when the constraint is checked,- -- an error is raised- | OnUpdateRestrict -- ^ prevents update of a referenced row- | OnUpdateCascade- -- ^ the updated values of the referenced column(s) should be copied- -- into the referencing row(s)- deriving (GHC.Generic,Show,Eq,Ord)-instance NFData OnUpdateClause---- | Render `OnUpdateClause`.-instance RenderSQL OnUpdateClause where- renderSQL = \case- OnUpdateNoAction -> "ON UPDATE NO ACTION"- OnUpdateRestrict -> "ON UPDATE RESTRICT"- OnUpdateCascade -> "ON UPDATE CASCADE"--{------------------------------------------DROP statements------------------------------------------}---- | >>> :{--- let--- definition :: Definition '["muh_schema" ::: schema, "public" ::: public] '["public" ::: public]--- definition = dropSchema #muh_schema--- :}------ >>> printSQL definition--- DROP SCHEMA "muh_schema";-dropSchema- :: Has sch schemas schema- => Alias sch- -> Definition schemas (Drop sch schemas)-dropSchema sch = UnsafeDefinition $ "DROP SCHEMA" <+> renderSQL sch <> ";"---- | `dropTable` removes a table from the schema.------ >>> :{--- let--- definition :: Definition '["public" ::: '["muh_table" ::: 'Table t]] (Public '[])--- definition = dropTable #muh_table--- :}------ >>> printSQL definition--- DROP TABLE "muh_table";-dropTable- :: ( Has sch schemas schema- , Has tab schema ('Table table))- => QualifiedAlias sch tab -- ^ table to remove- -> Definition schemas (Alter sch (Drop tab schema) schemas)-dropTable tab = UnsafeDefinition $ "DROP TABLE" <+> renderSQL tab <> ";"--{------------------------------------------ALTER statements------------------------------------------}---- | `alterTable` changes the definition of a table from the schema.-alterTable- :: (Has sch schemas schema, Has tab schema ('Table table0))- => QualifiedAlias sch tab -- ^ table to alter- -> AlterTable sch tab schemas table1 -- ^ alteration to perform- -> Definition schemas (Alter sch (Alter tab ('Table table1) schema) schemas)-alterTable tab alteration = UnsafeDefinition $- "ALTER TABLE"- <+> renderSQL tab- <+> renderAlterTable alteration- <> ";"---- | `alterTableRename` changes the name of a table from the schema.------ >>> printSQL $ alterTableRename #foo #bar--- ALTER TABLE "foo" RENAME TO "bar";-alterTableRename- :: (KnownSymbol table0, KnownSymbol table1)- => Alias table0 -- ^ table to rename- -> Alias table1 -- ^ what to rename it- -> Definition schema (Rename table0 table1 schema)-alterTableRename table0 table1 = UnsafeDefinition $- "ALTER TABLE" <+> renderSQL table0- <+> "RENAME TO" <+> renderSQL table1 <> ";"---- | An `AlterTable` describes the alteration to perform on the columns--- of a table.-newtype AlterTable- (sch :: Symbol)- (tab :: Symbol)- (schemas :: SchemasType)- (table :: TableType) =- UnsafeAlterTable {renderAlterTable :: ByteString}- deriving (GHC.Generic,Show,Eq,Ord,NFData)---- | An `addConstraint` adds a table constraint.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('["positive" ::: 'Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- definition = alterTable #tab (addConstraint #positive (check #col (#col .> 0)))--- in printSQL definition--- :}--- ALTER TABLE "tab" ADD CONSTRAINT "positive" CHECK (("col" > 0));-addConstraint- :: ( KnownSymbol alias- , Has sch schemas schema- , Has tab schema ('Table table0)- , table0 ~ (constraints :=> columns)- , table1 ~ (Create alias constraint constraints :=> columns) )- => Alias alias- -> TableConstraintExpression sch tab schemas constraint- -- ^ constraint to add- -> AlterTable sch tab schemas table1-addConstraint alias constraint = UnsafeAlterTable $- "ADD" <+> "CONSTRAINT" <+> renderSQL alias- <+> renderSQL constraint---- | A `dropConstraint` drops a table constraint.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- definition = alterTable #tab (dropConstraint #positive)--- in printSQL definition--- :}--- ALTER TABLE "tab" DROP CONSTRAINT "positive";-dropConstraint- :: ( KnownSymbol constraint- , Has sch schemas schema- , Has tab schema ('Table table0)- , table0 ~ (constraints :=> columns)- , table1 ~ (Drop constraint constraints :=> columns) )- => Alias constraint- -- ^ constraint to drop- -> AlterTable sch tab schemas table1-dropConstraint constraint = UnsafeAlterTable $- "DROP" <+> "CONSTRAINT" <+> renderSQL constraint---- | An `AddColumn` is either @NULL@ or has @DEFAULT@.-class AddColumn ty where- -- | `addColumn` adds a new column, initially filled with whatever- -- default value is given or with @NULL@.- --- -- >>> :{- -- let- -- definition :: Definition- -- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]- -- '["public" ::: '["tab" ::: 'Table ('[] :=>- -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4- -- , "col2" ::: 'Def :=> 'Null 'PGtext ])]]- -- definition = alterTable #tab (addColumn #col2 (text & nullable & default_ "foo"))- -- in printSQL definition- -- :}- -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL DEFAULT E'foo';- --- -- >>> :{- -- let- -- definition :: Definition- -- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]- -- '["public" ::: '["tab" ::: 'Table ('[] :=>- -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4- -- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]]- -- definition = alterTable #tab (addColumn #col2 (text & nullable))- -- in printSQL definition- -- :}- -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL;- addColumn- :: ( KnownSymbol column- , Has sch schemas schema- , Has tab schema ('Table table0)- , table0 ~ (constraints :=> columns) )- => Alias column -- ^ column to add- -> ColumnTypeExpression schemas ty -- ^ type of the new column- -> AlterTable sch tab schemas (constraints :=> Create column ty columns)- addColumn column ty = UnsafeAlterTable $- "ADD COLUMN" <+> renderSQL column <+> renderColumnTypeExpression ty-instance {-# OVERLAPPING #-} AddColumn ('Def :=> ty)-instance {-# OVERLAPPABLE #-} AddColumn ('NoDef :=> 'Null ty)---- | A `dropColumn` removes a column. Whatever data was in the column--- disappears. Table constraints involving the column are dropped, too.--- However, if the column is referenced by a foreign key constraint of--- another table, PostgreSQL will not silently drop that constraint.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=>--- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4--- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]--- definition = alterTable #tab (dropColumn #col2)--- in printSQL definition--- :}--- ALTER TABLE "tab" DROP COLUMN "col2";-dropColumn- :: ( KnownSymbol column- , Has sch schemas schema- , Has tab schema ('Table table0)- , table0 ~ (constraints :=> columns)- , table1 ~ (constraints :=> Drop column columns) )- => Alias column -- ^ column to remove- -> AlterTable sch tab schemas table1-dropColumn column = UnsafeAlterTable $- "DROP COLUMN" <+> renderSQL column---- | A `renameColumn` renames a column.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["foo" ::: 'NoDef :=> 'Null 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["bar" ::: 'NoDef :=> 'Null 'PGint4])]]--- definition = alterTable #tab (renameColumn #foo #bar)--- in printSQL definition--- :}--- ALTER TABLE "tab" RENAME COLUMN "foo" TO "bar";-renameColumn- :: ( KnownSymbol column0- , KnownSymbol column1- , Has sch schemas schema- , Has tab schema ('Table table0)- , table0 ~ (constraints :=> columns)- , table1 ~ (constraints :=> Rename column0 column1 columns) )- => Alias column0 -- ^ column to rename- -> Alias column1 -- ^ what to rename the column- -> AlterTable sch tab schemas table1-renameColumn column0 column1 = UnsafeAlterTable $- "RENAME COLUMN" <+> renderSQL column0 <+> "TO" <+> renderSQL column1---- | An `alterColumn` alters a single column.-alterColumn- :: ( KnownSymbol column- , Has sch schemas schema- , Has tab schema ('Table table0)- , table0 ~ (constraints :=> columns)- , Has column columns ty0- , table1 ~ (constraints :=> Alter column ty1 columns))- => Alias column -- ^ column to alter- -> AlterColumn schemas ty0 ty1 -- ^ alteration to perform- -> AlterTable sch tab schemas table1-alterColumn column alteration = UnsafeAlterTable $- "ALTER COLUMN" <+> renderSQL column <+> renderAlterColumn alteration---- | An `AlterColumn` describes the alteration to perform on a single column.-newtype AlterColumn (schemas :: SchemasType) (ty0 :: ColumnType) (ty1 :: ColumnType) =- UnsafeAlterColumn {renderAlterColumn :: ByteString}- deriving (GHC.Generic,Show,Eq,Ord,NFData)---- | A `setDefault` sets a new default for a column. Note that this doesn't--- affect any existing rows in the table, it just changes the default for--- future insert and update commands.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]]--- definition = alterTable #tab (alterColumn #col (setDefault 5))--- in printSQL definition--- :}--- ALTER TABLE "tab" ALTER COLUMN "col" SET DEFAULT 5;-setDefault- :: Expression '[] '[] 'Ungrouped schemas '[] '[] ty -- ^ default value to set- -> AlterColumn schemas (constraint :=> ty) ('Def :=> ty)-setDefault expression = UnsafeAlterColumn $- "SET DEFAULT" <+> renderExpression expression---- | A `dropDefault` removes any default value for a column.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]--- definition = alterTable #tab (alterColumn #col dropDefault)--- in printSQL definition--- :}--- ALTER TABLE "tab" ALTER COLUMN "col" DROP DEFAULT;-dropDefault :: AlterColumn schemas ('Def :=> ty) ('NoDef :=> ty)-dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"---- | A `setNotNull` adds a @NOT NULL@ constraint to a column.--- The constraint will be checked immediately, so the table data must satisfy--- the constraint before it can be added.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- definition = alterTable #tab (alterColumn #col setNotNull)--- in printSQL definition--- :}--- ALTER TABLE "tab" ALTER COLUMN "col" SET NOT NULL;-setNotNull- :: AlterColumn schemas (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)-setNotNull = UnsafeAlterColumn $ "SET NOT NULL"---- | A `dropNotNull` drops a @NOT NULL@ constraint from a column.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]--- definition = alterTable #tab (alterColumn #col dropNotNull)--- in printSQL definition--- :}--- ALTER TABLE "tab" ALTER COLUMN "col" DROP NOT NULL;-dropNotNull- :: AlterColumn schemas (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)-dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"---- | An `alterType` converts a column to a different data type.--- This will succeed only if each existing entry in the column can be--- converted to the new type by an implicit cast.------ >>> :{--- let--- definition :: Definition--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]--- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGnumeric])]]--- definition =--- alterTable #tab (alterColumn #col (alterType (numeric & notNullable)))--- in printSQL definition--- :}--- ALTER TABLE "tab" ALTER COLUMN "col" TYPE numeric NOT NULL;-alterType :: ColumnTypeExpression schemas ty -> AlterColumn schemas ty0 ty-alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty--{- | Create a view.->>> type ABC = '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4]->>> type BC = '["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4]->>> :{-let- definition :: Definition- '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC)]]- '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC), "bc" ::: 'View BC]]- definition =- createView #bc (select_ (#b :* #c) (from (table #abc)))-in printSQL definition-:}-CREATE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";--}-createView- :: (KnownSymbol sch, KnownSymbol vw, Has sch schemas schema)- => QualifiedAlias sch vw -- ^ the name of the view to add- -> Query '[] '[] schemas '[] view -- ^ query- -> Definition schemas (Alter sch (Create vw ('View view) schema) schemas)-createView alias query = UnsafeDefinition $- "CREATE" <+> "VIEW" <+> renderSQL alias <+> "AS"- <+> renderQuery query <> ";"---- | Drop a view.------ >>> :{--- let--- definition :: Definition--- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])--- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]]--- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]]--- definition = dropView #bc--- in printSQL definition--- :}--- DROP VIEW "bc";-dropView- :: (Has sch schemas schema, Has vw schema ('View view))- => QualifiedAlias sch vw -- ^ view to remove- -> Definition schemas (Alter sch (Drop vw schema) schemas)-dropView vw = UnsafeDefinition $ "DROP VIEW" <+> renderSQL vw <> ";"---- | Enumerated types are created using the `createTypeEnum` command, for example------ >>> printSQL $ (createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy") :: Definition (Public '[]) '["public" ::: '["mood" ::: 'Typedef ('PGenum '["sad","ok","happy"])]])--- CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');-createTypeEnum- :: (KnownSymbol enum, Has sch schemas schema, SOP.All KnownSymbol labels)- => QualifiedAlias sch enum- -- ^ name of the user defined enumerated type- -> NP PGlabel labels- -- ^ labels of the enumerated type- -> Definition schemas (Alter sch (Create enum ('Typedef ('PGenum labels)) schema) schemas)-createTypeEnum enum labels = UnsafeDefinition $- "CREATE" <+> "TYPE" <+> renderSQL enum <+> "AS" <+> "ENUM" <+>- parenthesized (renderSQL labels) <> ";"---- | Enumerated types can also be generated from a Haskell type, for example------ >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic--- >>> instance SOP.Generic Schwarma--- >>> instance SOP.HasDatatypeInfo Schwarma--- >>> :{--- let--- createSchwarma :: Definition (Public '[]) '["public" ::: '["schwarma" ::: 'Typedef (PG (Enumerated Schwarma))]]--- createSchwarma = createTypeEnumFrom @Schwarma #schwarma--- in--- printSQL createSchwarma--- :}--- CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');-createTypeEnumFrom- :: forall hask sch enum schemas schema.- ( SOP.Generic hask- , SOP.All KnownSymbol (LabelsPG hask)- , KnownSymbol enum- , Has sch schemas schema )- => QualifiedAlias sch enum- -- ^ name of the user defined enumerated type- -> Definition schemas (Alter sch (Create enum ('Typedef (PG (Enumerated hask))) schema) schemas)-createTypeEnumFrom enum = createTypeEnum enum- (SOP.hpure label :: NP PGlabel (LabelsPG hask))--{- | `createTypeComposite` creates a composite type. The composite type is-specified by a list of attribute names and data types.-->>> :{-type PGcomplex = 'PGcomposite- '[ "real" ::: 'NotNull 'PGfloat8- , "imaginary" ::: 'NotNull 'PGfloat8 ]-:}-->>> :{-let- setup :: Definition (Public '[]) '["public" ::: '["complex" ::: 'Typedef PGcomplex]]- setup = createTypeComposite #complex- (float8 `as` #real :* float8 `as` #imaginary)-in printSQL setup-:}-CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);--}-createTypeComposite- :: (KnownSymbol ty, Has sch schemas schema, SOP.SListI fields)- => QualifiedAlias sch ty- -- ^ name of the user defined composite type- -> NP (Aliased (TypeExpression schemas)) fields- -- ^ list of attribute names and data types- -> Definition schemas (Alter sch (Create ty ('Typedef ('PGcomposite fields)) schema) schemas)-createTypeComposite ty fields = UnsafeDefinition $- "CREATE" <+> "TYPE" <+> renderSQL ty <+> "AS" <+> parenthesized- (renderCommaSeparated renderField fields) <> ";"- where- renderField :: Aliased (TypeExpression schemas) x -> ByteString- renderField (typ `As` alias) =- renderSQL alias <+> renderSQL typ---- | Composite types can also be generated from a Haskell type, for example------ >>> data Complex = Complex {real :: Double, imaginary :: Double} deriving GHC.Generic--- >>> instance SOP.Generic Complex--- >>> instance SOP.HasDatatypeInfo Complex--- >>> type Schema = '["complex" ::: 'Typedef (PG (Composite Complex))]--- >>> :{--- let--- createComplex :: Definition (Public '[]) (Public Schema)--- createComplex = createTypeCompositeFrom @Complex #complex--- in--- printSQL createComplex--- :}--- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);-createTypeCompositeFrom- :: forall hask sch ty schemas schema.- ( SOP.All (FieldTyped schemas) (RowPG hask)- , KnownSymbol ty- , Has sch schemas schema )- => QualifiedAlias sch ty- -- ^ name of the user defined composite type- -> Definition schemas (Alter sch (Create ty ( 'Typedef (PG (Composite hask))) schema) schemas)-createTypeCompositeFrom ty = createTypeComposite ty- (SOP.hcpure (SOP.Proxy :: SOP.Proxy (FieldTyped schemas)) fieldtype- :: NP (Aliased (TypeExpression schemas)) (RowPG hask))--{-|-`createDomain` creates a new domain. A domain is essentially a data type-with constraints (restrictions on the allowed set of values).--Domains are useful for abstracting common constraints on fields-into a single location for maintenance. For example, several tables might-contain email address columns, all requiring the same `check` constraint-to verify the address syntax. Define a domain rather than setting up-each table's constraint individually.-->>> :{-let- createPositive :: Definition (Public '[]) (Public '["positive" ::: 'Typedef 'PGfloat4])- createPositive = createDomain #positive real (#value .> 0 .&& (#value & isNotNull))-in printSQL createPositive-:}-CREATE DOMAIN "positive" AS real CHECK ((("value" > 0) AND "value" IS NOT NULL));--}-createDomain- :: (Has sch schemas schema, KnownSymbol dom)- => QualifiedAlias sch dom- -> (forall nullity. TypeExpression schemas (nullity ty))- -> (forall tab. Condition '[] '[] 'Ungrouped schemas '[] '[tab ::: '["value" ::: 'Null ty]])- -> Definition schemas (Alter sch (Create alias ('Typedef ty) schema) schemas)-createDomain dom ty condition =- UnsafeDefinition $ "CREATE DOMAIN" <+> renderSQL dom- <+> "AS" <+> renderTypeExpression ty- <+> "CHECK" <+> parenthesized (renderSQL condition) <> ";"---- | Lift `PGTyped` to a field-class FieldTyped schemas ty where- fieldtype :: Aliased (TypeExpression schemas) ty-instance (KnownSymbol alias, PGTyped schemas ty)- => FieldTyped schemas (alias ::: ty) where- fieldtype = pgtype `As` Alias---- | Drop a type.------ >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic--- >>> instance SOP.Generic Schwarma--- >>> instance SOP.HasDatatypeInfo Schwarma--- >>> printSQL (dropType #schwarma :: Definition '["public" ::: '["schwarma" ::: 'Typedef (PG (Enumerated Schwarma))]] (Public '[]))--- DROP TYPE "schwarma";-dropType- :: (Has sch schemas schema, Has td schema ('Typedef ty))- => QualifiedAlias sch td- -- ^ name of the user defined type- -> Definition schemas (Alter sch (Drop td schema) schemas)-dropType tydef = UnsafeDefinition $ "DROP" <+> "TYPE" <+> renderSQL tydef <> ";"---- | `ColumnTypeExpression`s are used in `createTable` commands.-newtype ColumnTypeExpression (schemas :: SchemasType) (ty :: ColumnType)- = UnsafeColumnTypeExpression { renderColumnTypeExpression :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL (ColumnTypeExpression schemas ty) where- renderSQL = renderColumnTypeExpression---- | used in `createTable` commands as a column constraint to note that--- @NULL@ may be present in a column-nullable- :: TypeExpression schemas (nullity ty)- -> ColumnTypeExpression schemas ('NoDef :=> 'Null ty)-nullable ty = UnsafeColumnTypeExpression $ renderSQL ty <+> "NULL"---- | used in `createTable` commands as a column constraint to ensure--- @NULL@ is not present in a column-notNullable- :: TypeExpression schemas (nullity ty)- -> ColumnTypeExpression schemas ('NoDef :=> 'NotNull ty)-notNullable ty = UnsafeColumnTypeExpression $ renderSQL ty <+> "NOT NULL"---- | used in `createTable` commands as a column constraint to give a default-default_- :: Expression '[] '[] 'Ungrouped schemas '[] '[] ty- -> ColumnTypeExpression schemas ('NoDef :=> ty)- -> ColumnTypeExpression schemas ('Def :=> ty)-default_ x ty = UnsafeColumnTypeExpression $- renderSQL ty <+> "DEFAULT" <+> renderExpression x---- | not a true type, but merely a notational convenience for creating--- unique identifier columns with type `PGint2`-serial2, smallserial- :: ColumnTypeExpression schemas ('Def :=> 'NotNull 'PGint2)-serial2 = UnsafeColumnTypeExpression "serial2"-smallserial = UnsafeColumnTypeExpression "smallserial"--- | not a true type, but merely a notational convenience for creating--- unique identifier columns with type `PGint4`-serial4, serial- :: ColumnTypeExpression schemas ('Def :=> 'NotNull 'PGint4)-serial4 = UnsafeColumnTypeExpression "serial4"-serial = UnsafeColumnTypeExpression "serial"--- | not a true type, but merely a notational convenience for creating--- unique identifier columns with type `PGint8`-serial8, bigserial- :: ColumnTypeExpression schemas ('Def :=> 'NotNull 'PGint8)-serial8 = UnsafeColumnTypeExpression "serial8"-bigserial = UnsafeColumnTypeExpression "bigserial"+Description: data definition language+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++data definition language+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Definition+ ( -- * Definition+ Definition (..)+ , (>>>)+ , manipulation_+ ) where++import Control.Category+import Control.DeepSeq+import Data.ByteString+import Data.Monoid+import Prelude hiding ((.), id)++import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{-----------------------------------------+statements+-----------------------------------------}++-- | A `Definition` is a statement that changes the schemas of the+-- database, like a `Squeal.PostgreSQL.Definition.Table.createTable`,+-- `Squeal.PostgreSQL.Definition.Table.dropTable`,+-- or `Squeal.PostgreSQL.Definition.Table.alterTable` command.+-- `Definition`s may be composed using the `>>>` operator.+newtype Definition+ (db0 :: SchemasType)+ (db1 :: SchemasType)+ = UnsafeDefinition { renderDefinition :: ByteString }+ deriving (GHC.Generic,Show,Eq,Ord,NFData)++instance RenderSQL (Definition db0 db1) where+ renderSQL = renderDefinition++instance Category Definition where+ id = UnsafeDefinition ";"+ ddl1 . ddl0 = UnsafeDefinition $+ renderSQL ddl0 <> "\n" <> renderSQL ddl1++instance db0 ~ db1 => Semigroup (Definition db0 db1) where (<>) = (>>>)+instance db0 ~ db1 => Monoid (Definition db0 db1) where mempty = id++-- | A `Manipulation` without input or output can be run as a statement+-- along with other `Definition`s, by embedding it using `manipulation_`.+manipulation_+ :: Manipulation '[] db '[] '[]+ -- ^ no input or output+ -> Definition db db+manipulation_ = UnsafeDefinition . (<> ";") . renderSQL
+ src/Squeal/PostgreSQL/Definition/Constraint.hs view
@@ -0,0 +1,341 @@+{-|+Module: Squeal.PostgreSQL.Definition.Constraint+Description: constraint expressions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++constraint expressions+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.Constraint+ ( -- * Table Constraints+ TableConstraintExpression (..)+ , check+ , unique+ , primaryKey+ -- ** Foreign Keys+ , foreignKey+ , ForeignKeyed+ , OnDeleteClause (..)+ , OnUpdateClause (..)+ ) where++import Control.DeepSeq+import Data.ByteString+import GHC.TypeLits++import qualified Generics.SOP as SOP+import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++-- | Data types are a way to limit the kind of data that can be stored in a+-- table. For many applications, however, the constraint they provide is+-- too coarse. For example, a column containing a product price should+-- probably only accept positive values. But there is no standard data type+-- that accepts only positive numbers. Another issue is that you might want+-- to constrain column data with respect to other columns or rows.+-- For example, in a table containing product information,+-- there should be only one row for each product number.+-- `TableConstraint`s give you as much control over the data in your tables+-- as you wish. If a user attempts to store data in a column that would+-- violate a constraint, an error is raised. This applies+-- even if the value came from the default value definition.+newtype TableConstraintExpression+ (sch :: Symbol)+ (tab :: Symbol)+ (db :: SchemasType)+ (constraint :: TableConstraint)+ = UnsafeTableConstraintExpression+ { renderTableConstraintExpression :: ByteString }+ deriving (GHC.Generic,Show,Eq,Ord,NFData)+instance RenderSQL+ (TableConstraintExpression sch tab db constraint) where+ renderSQL = renderTableConstraintExpression++{-| A `check` constraint is the most generic `TableConstraint` type.+It allows you to specify that the value in a certain column must satisfy+a Boolean (truth-value) expression.++>>> :{+type Schema = '[+ "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[+ "a" ::: 'NoDef :=> 'NotNull 'PGint4,+ "b" ::: 'NoDef :=> 'NotNull 'PGint4+ ])]+:}++>>> :{+let+ definition :: Definition (Public '[]) (Public Schema)+ definition = createTable #tab+ ( (int & notNullable) `as` #a :*+ (int & notNullable) `as` #b )+ ( check (#a :* #b) (#a .> #b) `as` #inequality )+:}++>>> printSQL definition+CREATE TABLE "tab" ("a" int NOT NULL, "b" int NOT NULL, CONSTRAINT "inequality" CHECK (("a" > "b")));+-}+check+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , HasAll aliases (TableToRow table) subcolumns )+ => NP Alias aliases+ -- ^ specify the subcolumns which are getting checked+ -> (forall t. Condition 'Ungrouped '[] '[] db '[] '[t ::: subcolumns])+ -- ^ a closed `Condition` on those subcolumns+ -> TableConstraintExpression sch tab db ('Check aliases)+check _cols condition = UnsafeTableConstraintExpression $+ "CHECK" <+> parenthesized (renderSQL condition)++{-| A `unique` constraint ensure that the data contained in a column,+or a group of columns, is unique among all the rows in the table.++>>> :{+type Schema = '[+ "tab" ::: 'Table( '[ "uq_a_b" ::: 'Unique '["a","b"]] :=> '[+ "a" ::: 'NoDef :=> 'Null 'PGint4,+ "b" ::: 'NoDef :=> 'Null 'PGint4+ ])]+:}++>>> :{+let+ definition :: Definition (Public '[]) (Public Schema)+ definition = createTable #tab+ ( (int & nullable) `as` #a :*+ (int & nullable) `as` #b )+ ( unique (#a :* #b) `as` #uq_a_b )+:}++>>> printSQL definition+CREATE TABLE "tab" ("a" int NULL, "b" int NULL, CONSTRAINT "uq_a_b" UNIQUE ("a", "b"));+-}+unique+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , HasAll aliases (TableToRow table) subcolumns )+ => NP Alias aliases+ -- ^ specify subcolumns which together are unique for each row+ -> TableConstraintExpression sch tab db ('Unique aliases)+unique columns = UnsafeTableConstraintExpression $+ "UNIQUE" <+> parenthesized (renderSQL columns)++{-| A `primaryKey` constraint indicates that a column, or group of columns,+can be used as a unique identifier for rows in the table.+This requires that the values be both unique and not null.++>>> :{+type Schema = '[+ "tab" ::: 'Table ('[ "pk_id" ::: 'PrimaryKey '["id"]] :=> '[+ "id" ::: 'Def :=> 'NotNull 'PGint4,+ "name" ::: 'NoDef :=> 'NotNull 'PGtext+ ])]+:}++>>> :{+let+ definition :: Definition (Public '[]) (Public Schema)+ definition = createTable #tab+ ( serial `as` #id :*+ (text & notNullable) `as` #name )+ ( primaryKey #id `as` #pk_id )+:}++>>> printSQL definition+CREATE TABLE "tab" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_id" PRIMARY KEY ("id"));+-}+primaryKey+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , HasAll aliases (TableToColumns table) subcolumns+ , AllNotNull subcolumns )+ => NP Alias aliases+ -- ^ specify the subcolumns which together form a primary key.+ -> TableConstraintExpression sch tab db ('PrimaryKey aliases)+primaryKey columns = UnsafeTableConstraintExpression $+ "PRIMARY KEY" <+> parenthesized (renderSQL columns)++{-| A `foreignKey` specifies that the values in a column+(or a group of columns) must match the values appearing in some row of+another table. We say this maintains the referential integrity+between two related tables.++>>> :{+type Schema =+ '[ "users" ::: 'Table (+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext+ ])+ , "emails" ::: 'Table (+ '[ "pk_emails" ::: 'PrimaryKey '["id"]+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]+ ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4+ , "email" ::: 'NoDef :=> 'Null 'PGtext+ ])+ ]+:}++>>> :{+let+ setup :: Definition (Public '[]) (Public Schema)+ setup =+ createTable #users+ ( serial `as` #id :*+ (text & notNullable) `as` #name )+ ( primaryKey #id `as` #pk_users ) >>>+ createTable #emails+ ( serial `as` #id :*+ (int & notNullable) `as` #user_id :*+ (text & nullable) `as` #email )+ ( primaryKey #id `as` #pk_emails :*+ foreignKey #user_id #users #id+ OnDeleteCascade OnUpdateCascade `as` #fk_user_id )+in printSQL setup+:}+CREATE TABLE "users" ("id" serial, "name" text NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"));+CREATE TABLE "emails" ("id" serial, "user_id" int NOT NULL, "email" text NULL, CONSTRAINT "pk_emails" PRIMARY KEY ("id"), CONSTRAINT "fk_user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE);++A `foreignKey` can even be a table self-reference.++>>> :{+type Schema =+ '[ "employees" ::: 'Table (+ '[ "employees_pk" ::: 'PrimaryKey '["id"]+ , "employees_employer_fk" ::: 'ForeignKey '["employer_id"] "employees" '["id"]+ ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext+ , "employer_id" ::: 'NoDef :=> 'Null 'PGint4+ ])+ ]+:}++>>> :{+let+ setup :: Definition (Public '[]) (Public Schema)+ setup =+ createTable #employees+ ( serial `as` #id :*+ (text & notNullable) `as` #name :*+ (integer & nullable) `as` #employer_id )+ ( primaryKey #id `as` #employees_pk :*+ foreignKey #employer_id #employees #id+ OnDeleteCascade OnUpdateCascade `as` #employees_employer_fk )+in printSQL setup+:}+CREATE TABLE "employees" ("id" serial, "name" text NOT NULL, "employer_id" integer NULL, CONSTRAINT "employees_pk" PRIMARY KEY ("id"), CONSTRAINT "employees_employer_fk" FOREIGN KEY ("employer_id") REFERENCES "employees" ("id") ON DELETE CASCADE ON UPDATE CASCADE);+-}+foreignKey+ :: (ForeignKeyed db sch schema child parent+ table reftable+ columns refcolumns+ constraints cols+ reftys tys )+ => NP Alias columns+ -- ^ column or columns in the table+ -> Alias parent+ -- ^ reference table+ -> NP Alias refcolumns+ -- ^ reference column or columns in the reference table+ -> OnDeleteClause+ -- ^ what to do when reference is deleted+ -> OnUpdateClause+ -- ^ what to do when reference is updated+ -> TableConstraintExpression sch child db+ ('ForeignKey columns parent refcolumns)+foreignKey keys parent refs ondel onupd = UnsafeTableConstraintExpression $+ "FOREIGN KEY" <+> parenthesized (renderSQL keys)+ <+> "REFERENCES" <+> renderSQL parent+ <+> parenthesized (renderSQL refs)+ <+> renderSQL ondel+ <+> renderSQL onupd++-- | A constraint synonym between types involved in a foreign key constraint.+type ForeignKeyed db+ sch+ schema+ child parent+ table reftable+ columns refcolumns+ constraints cols+ reftys tys =+ ( Has sch db schema+ , Has child schema ('Table table)+ , Has parent schema ('Table reftable)+ , HasAll columns (TableToColumns table) tys+ , reftable ~ (constraints :=> cols)+ , HasAll refcolumns cols reftys+ , SOP.AllZip SamePGType tys reftys+ , Uniquely refcolumns constraints )++-- | `OnDeleteClause` indicates what to do with rows that reference a deleted row.+data OnDeleteClause+ = OnDeleteNoAction+ -- ^ if any referencing rows still exist when the constraint is checked,+ -- an error is raised+ | OnDeleteRestrict -- ^ prevents deletion of a referenced row+ | OnDeleteCascade+ -- ^ specifies that when a referenced row is deleted,+ -- row(s) referencing it should be automatically deleted as well+ deriving (GHC.Generic,Show,Eq,Ord)+instance NFData OnDeleteClause+-- | Render `OnDeleteClause`.+instance RenderSQL OnDeleteClause where+ renderSQL = \case+ OnDeleteNoAction -> "ON DELETE NO ACTION"+ OnDeleteRestrict -> "ON DELETE RESTRICT"+ OnDeleteCascade -> "ON DELETE CASCADE"++-- | Analagous to `OnDeleteClause` there is also `OnUpdateClause` which is invoked+-- when a referenced column is changed (updated).+data OnUpdateClause+ = OnUpdateNoAction+ -- ^ if any referencing rows has not changed when the constraint is checked,+ -- an error is raised+ | OnUpdateRestrict -- ^ prevents update of a referenced row+ | OnUpdateCascade+ -- ^ the updated values of the referenced column(s) should be copied+ -- into the referencing row(s)+ deriving (GHC.Generic,Show,Eq,Ord)+instance NFData OnUpdateClause++-- | Render `OnUpdateClause`.+instance RenderSQL OnUpdateClause where+ renderSQL = \case+ OnUpdateNoAction -> "ON UPDATE NO ACTION"+ OnUpdateRestrict -> "ON UPDATE RESTRICT"+ OnUpdateCascade -> "ON UPDATE CASCADE"
+ src/Squeal/PostgreSQL/Definition/Function.hs view
@@ -0,0 +1,249 @@+{-|+Module: Squeal.PostgreSQL.Definition.Function+Description: create and drop functions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++create and drop functions+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.Function+ ( -- * Create+ createFunction+ , createOrReplaceFunction+ , createSetFunction+ , createOrReplaceSetFunction+ -- * Drop+ , dropFunction+ , dropFunctionIfExists+ -- * Function Definition+ , FunctionDefinition(..)+ , languageSqlExpr+ , languageSqlQuery+ ) where++import Control.DeepSeq+import Data.ByteString+import GHC.TypeLits++import qualified Generics.SOP as SOP+import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Type+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Query.Values+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{- | Create a function.++>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))+>>> :{+let+ definition :: Definition (Public '[]) (Public '["fn" ::: Fn])+ definition = createFunction #fn (int4 *: int4) int4 $+ languageSqlExpr (param @1 * param @2 + 1)+in printSQL definition+:}+CREATE FUNCTION "fn" (int4, int4) RETURNS int4 language sql as $$ SELECT * FROM (VALUES (((($1 :: int4) * ($2 :: int4)) + (1 :: int4)))) AS t ("ret") $$;+-}+createFunction+ :: ( Has sch db schema+ , KnownSymbol fun+ , SOP.SListI args )+ => QualifiedAlias sch fun -- ^ function alias+ -> NP (TypeExpression db) args -- ^ arguments+ -> TypeExpression db ret -- ^ return type+ -> FunctionDefinition db args ('Returns ret) -- ^ function definition+ -> Definition db (Alter sch (Create fun ('Function (args :=> 'Returns ret)) schema) db)+createFunction fun args ret fundef = UnsafeDefinition $+ "CREATE" <+> "FUNCTION" <+> renderSQL fun+ <+> parenthesized (renderCommaSeparated renderSQL args)+ <+> "RETURNS" <+> renderSQL ret <+> renderSQL fundef <> ";"++{- | Create or replace a function.+It is not possible to change the name or argument types+or return type of a function this way.++>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))+>>> :{+let+ definition :: Definition (Public '["fn" ::: Fn]) (Public '["fn" ::: Fn])+ definition =+ createOrReplaceFunction #fn+ (int4 *: int4) int4 $+ languageSqlExpr (param @1 @('Null 'PGint4) * param @2 @('Null 'PGint4) + 1)+in printSQL definition+:}+CREATE OR REPLACE FUNCTION "fn" (int4, int4) RETURNS int4 language sql as $$ SELECT * FROM (VALUES (((($1 :: int4) * ($2 :: int4)) + (1 :: int4)))) AS t ("ret") $$;+-}+createOrReplaceFunction+ :: ( Has sch db schema+ , KnownSymbol fun+ , SOP.SListI args )+ => QualifiedAlias sch fun -- ^ function alias+ -> NP (TypeExpression db) args -- ^ arguments+ -> TypeExpression db ret -- ^ return type+ -> FunctionDefinition db args ('Returns ret) -- ^ function definition+ -> Definition db (Alter sch (CreateOrReplace fun ('Function (args :=> 'Returns ret)) schema) db)+createOrReplaceFunction fun args ret fundef = UnsafeDefinition $+ "CREATE" <+> "OR" <+> "REPLACE" <+> "FUNCTION" <+> renderSQL fun+ <+> parenthesized (renderCommaSeparated renderSQL args)+ <+> "RETURNS" <+> renderSQL ret <+> renderSQL fundef <> ";"++-- | Use a parameterized `Expression` as a function body+languageSqlExpr+ :: Expression 'Ungrouped '[] '[] db args '[] ret+ -- ^ function body+ -> FunctionDefinition db args ('Returns ret)+languageSqlExpr expr = UnsafeFunctionDefinition $+ "language sql as"+ <+> "$$" <+> renderSQL (values_ (expr `as` #ret)) <+> "$$"++-- | Use a parametrized `Query` as a function body+languageSqlQuery+ :: Query '[] '[] db args rets+ -- ^ function body+ -> FunctionDefinition db args ('ReturnsTable rets)+languageSqlQuery qry = UnsafeFunctionDefinition $+ "language sql as" <+> "$$" <+> renderSQL qry <+> "$$"++{- | Create a set function.++>>> type Tab = 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])+>>> type Fn = 'Function ('[ 'Null 'PGint4, 'Null 'PGint4] :=> 'ReturnsTable '["ret" ::: 'Null 'PGint4])+>>> :{+let+ definition :: Definition (Public '["tab" ::: Tab]) (Public '["tab" ::: Tab, "fn" ::: Fn])+ definition = createSetFunction #fn (int4 *: int4) (int4 `as` #ret) $+ languageSqlQuery (select_ ((param @1 * param @2 + #col) `as` #ret) (from (table #tab)))+in printSQL definition+:}+CREATE FUNCTION "fn" (int4, int4) RETURNS TABLE ("ret" int4) language sql as $$ SELECT ((($1 :: int4) * ($2 :: int4)) + "col") AS "ret" FROM "tab" AS "tab" $$;+-}+createSetFunction+ :: ( Has sch db schema+ , KnownSymbol fun+ , SOP.SListI args+ , SOP.SListI rets )+ => QualifiedAlias sch fun -- ^ function alias+ -> NP (TypeExpression db) args -- ^ arguments+ -> NP (Aliased (TypeExpression db)) rets -- ^ return type+ -> FunctionDefinition db args ('ReturnsTable rets) -- ^ function definition+ -> Definition db (Alter sch (Create fun ('Function (args :=> 'ReturnsTable rets)) schema) db)+createSetFunction fun args rets fundef = UnsafeDefinition $+ "CREATE" <+> "FUNCTION" <+> renderSQL fun+ <+> parenthesized (renderCommaSeparated renderSQL args)+ <+> "RETURNS" <+> "TABLE"+ <+> parenthesized (renderCommaSeparated renderRet rets)+ <+> renderSQL fundef <> ";"+ where+ renderRet :: Aliased (TypeExpression s) r -> ByteString+ renderRet (ty `As` col) = renderSQL col <+> renderSQL ty++{- | Create or replace a set function.++>>> type Tab = 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])+>>> type Fn = 'Function ('[ 'Null 'PGint4, 'Null 'PGint4] :=> 'ReturnsTable '["ret" ::: 'Null 'PGint4])+>>> :{+let+ definition :: Definition (Public '["tab" ::: Tab, "fn" ::: Fn]) (Public '["tab" ::: Tab, "fn" ::: Fn])+ definition = createOrReplaceSetFunction #fn (int4 *: int4) (int4 `as` #ret) $+ languageSqlQuery (select_ ((param @1 * param @2 + #col) `as` #ret) (from (table #tab)))+in printSQL definition+:}+CREATE OR REPLACE FUNCTION "fn" (int4, int4) RETURNS TABLE ("ret" int4) language sql as $$ SELECT ((($1 :: int4) * ($2 :: int4)) + "col") AS "ret" FROM "tab" AS "tab" $$;+-}+createOrReplaceSetFunction+ :: ( Has sch db schema+ , KnownSymbol fun+ , SOP.SListI args+ , SOP.SListI rets )+ => QualifiedAlias sch fun -- ^ function alias+ -> NP (TypeExpression db) args -- ^ arguments+ -> NP (Aliased (TypeExpression db)) rets -- ^ return type+ -> FunctionDefinition db args ('ReturnsTable rets) -- ^ function definition+ -> Definition db (Alter sch (CreateOrReplace fun ('Function (args :=> 'ReturnsTable rets)) schema) db)+createOrReplaceSetFunction fun args rets fundef = UnsafeDefinition $+ "CREATE" <+> "OR" <+> "REPLACE" <+> "FUNCTION" <+> renderSQL fun+ <+> parenthesized (renderCommaSeparated renderSQL args)+ <+> "RETURNS" <+> "TABLE"+ <+> parenthesized (renderCommaSeparated renderRet rets)+ <+> renderSQL fundef <> ";"+ where+ renderRet :: Aliased (TypeExpression s) r -> ByteString+ renderRet (ty `As` col) = renderSQL col <+> renderSQL ty++{- | Drop a function.++>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))+>>> :{+let+ definition :: Definition (Public '["fn" ::: Fn]) (Public '[])+ definition = dropFunction #fn+in printSQL definition+:}+DROP FUNCTION "fn";+-}+dropFunction+ :: (Has sch db schema, KnownSymbol fun)+ => QualifiedAlias sch fun+ -- ^ function alias+ -> Definition db (Alter sch (DropSchemum fun 'Function schema) db)+dropFunction fun = UnsafeDefinition $+ "DROP FUNCTION" <+> renderSQL fun <> ";"++{- | Drop a function.++>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))+>>> :{+let+ definition :: Definition (Public '[]) (Public '[])+ definition = dropFunctionIfExists #fn+in printSQL definition+:}+DROP FUNCTION IF EXISTS "fn";+-}+dropFunctionIfExists+ :: (Has sch db schema, KnownSymbol fun)+ => QualifiedAlias sch fun+ -- ^ function alias+ -> Definition db (Alter sch (DropSchemumIfExists fun 'Function schema) db)+dropFunctionIfExists fun = UnsafeDefinition $+ "DROP FUNCTION IF EXISTS" <+> renderSQL fun <> ";"++{- | Body of a user defined function-}+newtype FunctionDefinition db args ret = UnsafeFunctionDefinition+ { renderFunctionDefinition :: ByteString }+ deriving (Eq,Show,GHC.Generic,NFData)+instance RenderSQL (FunctionDefinition db args ret) where+ renderSQL = renderFunctionDefinition
+ src/Squeal/PostgreSQL/Definition/Index.hs view
@@ -0,0 +1,186 @@+{-|+Module: Squeal.PostgreSQL.Definition.Index+Description: create and drop indexes+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++create and drop indexes+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.Index+ ( -- * Create+ createIndex+ , createIndexIfNotExists+ -- * Drop+ , dropIndex+ , dropIndexIfExists+ -- * Index Method+ , IndexMethod (..)+ , btree+ , hash+ , gist+ , spgist+ , gin+ , brin+ ) where++import Data.ByteString+import GHC.TypeLits++import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Expression.Sort+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL+-- >>> :set -XPolyKinds++{- | Create an index.++>>> :{+type Table = '[] :=>+ '[ "a" ::: 'NoDef :=> 'Null 'PGint4+ , "b" ::: 'NoDef :=> 'Null 'PGfloat4 ]+:}++>>> :{+let+ setup :: Definition (Public '[]) (Public '["tab" ::: 'Table Table, "ix" ::: 'Index 'Btree])+ setup =+ createTable #tab (nullable int `as` #a :* nullable real `as` #b) Nil >>>+ createIndex #ix #tab btree [#a & AscNullsFirst, #b & AscNullsLast]+in printSQL setup+:}+CREATE TABLE "tab" ("a" int NULL, "b" real NULL);+CREATE INDEX "ix" ON "tab" USING btree (("a") ASC NULLS FIRST, ("b") ASC NULLS LAST);+-}+createIndex+ :: (Has sch db schema, Has tab schema ('Table table), KnownSymbol ix)+ => Alias ix -- ^ index alias+ -> QualifiedAlias sch tab -- ^ table alias+ -> IndexMethod method -- ^ index method+ -> [SortExpression 'Ungrouped '[] '[] db '[] '[tab ::: TableToRow table]]+ -- ^ sorted columns+ -> Definition db (Alter sch (Create ix ('Index method) schema) db)+createIndex ix tab method cols = UnsafeDefinition $+ "CREATE" <+> "INDEX" <+> renderSQL ix <+> "ON" <+> renderSQL tab+ <+> "USING" <+> renderSQL method+ <+> parenthesized (commaSeparated (renderIndex <$> cols))+ <> ";"+ where+ renderIndex = \case+ Asc expression -> parenthesized (renderSQL expression) <+> "ASC"+ Desc expression -> parenthesized (renderSQL expression) <+> "DESC"+ AscNullsFirst expression -> parenthesized (renderSQL expression)+ <+> "ASC NULLS FIRST"+ DescNullsFirst expression -> parenthesized (renderSQL expression)+ <+> "DESC NULLS FIRST"+ AscNullsLast expression -> parenthesized (renderSQL expression)+ <+> "ASC NULLS LAST"+ DescNullsLast expression -> parenthesized (renderSQL expression)+ <+> "DESC NULLS LAST"++-- | Create an index if it doesn't exist.+createIndexIfNotExists+ :: (Has sch db schema, Has tab schema ('Table table), KnownSymbol ix)+ => Alias ix -- ^ index alias+ -> QualifiedAlias sch tab -- ^ table alias+ -> IndexMethod method -- ^ index method+ -> [SortExpression 'Ungrouped '[] '[] db '[] '[tab ::: TableToRow table]]+ -- ^ sorted columns+ -> Definition db (Alter sch (CreateIfNotExists ix ('Index method) schema) db)+createIndexIfNotExists ix tab method cols = UnsafeDefinition $+ "CREATE INDEX IF NOT EXISTS" <+> renderSQL ix <+> "ON" <+> renderSQL tab+ <+> "USING" <+> renderSQL method+ <+> parenthesized (commaSeparated (renderIndex <$> cols))+ <> ";"+ where+ renderIndex = \case+ Asc expression -> parenthesized (renderSQL expression) <+> "ASC"+ Desc expression -> parenthesized (renderSQL expression) <+> "DESC"+ AscNullsFirst expression -> parenthesized (renderSQL expression)+ <+> "ASC NULLS FIRST"+ DescNullsFirst expression -> parenthesized (renderSQL expression)+ <+> "DESC NULLS FIRST"+ AscNullsLast expression -> parenthesized (renderSQL expression)+ <+> "ASC NULLS LAST"+ DescNullsLast expression -> parenthesized (renderSQL expression)+ <+> "DESC NULLS LAST"++{- |+PostgreSQL provides several index types:+B-tree, Hash, GiST, SP-GiST, GIN and BRIN.+Each index type uses a different algorithm+that is best suited to different types of queries.+-}+newtype IndexMethod ty = UnsafeIndexMethod {renderIndexMethod :: ByteString}+ deriving stock (Eq, Ord, Show, GHC.Generic)+instance RenderSQL (IndexMethod ty) where renderSQL = renderIndexMethod+-- | B-trees can handle equality and range queries on data+-- that can be sorted into some ordering.+btree :: IndexMethod 'Btree+btree = UnsafeIndexMethod "btree"+-- | Hash indexes can only handle simple equality comparisons.+hash :: IndexMethod 'Hash+hash = UnsafeIndexMethod "hash"+-- | GiST indexes are not a single kind of index,+-- but rather an infrastructure within which many different+-- indexing strategies can be implemented.+gist :: IndexMethod 'Gist+gist = UnsafeIndexMethod "gist"+-- | SP-GiST indexes, like GiST indexes,+-- offer an infrastructure that supports various kinds of searches.+spgist :: IndexMethod 'Spgist+spgist = UnsafeIndexMethod "spgist"+-- | GIN indexes are “inverted indexes” which are appropriate for+-- data values that contain multiple component values, such as arrays.+gin :: IndexMethod 'Gin+gin = UnsafeIndexMethod "gin"+-- | BRIN indexes (a shorthand for Block Range INdexes) store summaries+-- about the values stored in consecutive physical block ranges of a table.+brin :: IndexMethod 'Brin+brin = UnsafeIndexMethod "brin"++-- | Drop an index.+--+-- >>> printSQL (dropIndex #ix :: Definition (Public '["ix" ::: 'Index 'Btree]) (Public '[]))+-- DROP INDEX "ix";+dropIndex+ :: (Has sch db schema, KnownSymbol ix)+ => QualifiedAlias sch ix -- index alias+ -> Definition db (Alter sch (DropSchemum ix 'Index schema) db)+dropIndex ix = UnsafeDefinition $ "DROP INDEX" <+> renderSQL ix <> ";"++-- | Drop an index if it exists.+dropIndexIfExists+ :: (Has sch db schema, KnownSymbol ix)+ => QualifiedAlias sch ix -- index alias+ -> Definition db (Alter sch (DropSchemumIfExists ix 'Index schema) db)+dropIndexIfExists ix = UnsafeDefinition $+ "DROP INDEX IF EXISTS" <+> renderSQL ix <> ";"
+ src/Squeal/PostgreSQL/Definition/Schema.hs view
@@ -0,0 +1,113 @@+{-|+Module: Squeal.PostgreSQL.Definition.Schema+Description: create and drop schemas+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++create and drop schemas+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.Schema+ ( -- * Create+ createSchema+ , createSchemaIfNotExists+ -- * Drop+ , dropSchemaCascade+ , dropSchemaCascadeIfExists+ ) where++import GHC.TypeLits++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{- |+`createSchema` enters a new schema into the current database.+The schema name must be distinct from the name of any existing schema+in the current database.++A schema is essentially a namespace: it contains named objects+(tables, data types, functions, and operators) whose names+can duplicate those of other objects existing in other schemas.+Named objects are accessed by `QualifiedAlias`es with the schema+name as a prefix.++>>> :{+let+ definition :: Definition '["public" ::: '[]] '["public" ::: '[], "my_schema" ::: '[]]+ definition = createSchema #my_schema+in printSQL definition+:}+CREATE SCHEMA "my_schema";+-}+createSchema+ :: KnownSymbol sch+ => Alias sch -- ^ schema alias+ -> Definition db (Create sch '[] db)+createSchema sch = UnsafeDefinition $+ "CREATE" <+> "SCHEMA" <+> renderSQL sch <> ";"++{- | Create a schema if it does not yet exist.-}+createSchemaIfNotExists+ :: (KnownSymbol sch, Has sch db schema)+ => Alias sch -- ^ schema alias+ -> Definition db (CreateIfNotExists sch '[] db)+createSchemaIfNotExists sch = UnsafeDefinition $+ "CREATE" <+> "SCHEMA" <+> "IF" <+> "NOT" <+> "EXISTS"+ <+> renderSQL sch <> ";"++-- | Drop a schema.+-- Automatically drop objects (tables, functions, etc.)+-- that are contained in the schema.+--+-- >>> :{+-- let+-- definition :: Definition '["muh_schema" ::: schema, "public" ::: public] '["public" ::: public]+-- definition = dropSchemaCascade #muh_schema+-- :}+--+-- >>> printSQL definition+-- DROP SCHEMA "muh_schema" CASCADE;+dropSchemaCascade+ :: KnownSymbol sch+ => Alias sch -- ^ schema alias+ -> Definition db (Drop sch db)+dropSchemaCascade sch = UnsafeDefinition $+ "DROP SCHEMA" <+> renderSQL sch <+> "CASCADE;"++-- | Drop a schema if it exists.+-- Automatically drop objects (tables, functions, etc.)+-- that are contained in the schema.+dropSchemaCascadeIfExists+ :: KnownSymbol sch+ => Alias sch -- ^ schema alias+ -> Definition db (DropIfExists sch db)+dropSchemaCascadeIfExists sch = UnsafeDefinition $+ "DROP SCHEMA IF EXISTS" <+> renderSQL sch <+> "CASCADE;"
+ src/Squeal/PostgreSQL/Definition/Table.hs view
@@ -0,0 +1,497 @@+{-|+Module: Squeal.PostgreSQL.Definition.Table+Description: create, drop and alter tables+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++create, drop and alter tables+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.Table+ ( -- * Create+ createTable+ , createTableIfNotExists+ -- * Drop+ , dropTable+ , dropTableIfExists+ -- * Alter+ , alterTable+ , alterTableIfExists+ , alterTableRename+ , alterTableIfExistsRename+ , AlterTable (..)+ -- ** Constraints+ , addConstraint+ , dropConstraint+ -- ** Columns+ , AddColumn (..)+ , dropColumn+ , renameColumn+ , alterColumn+ , AlterColumn (..)+ , setDefault+ , dropDefault+ , setNotNull+ , dropNotNull+ , alterType+ ) where++import Control.DeepSeq+import Data.ByteString+import GHC.TypeLits++import qualified Generics.SOP as SOP+import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Definition.Constraint+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Type+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{- | `createTable` adds a table to the schema.++>>> :set -XOverloadedLabels+>>> :{+type Table = '[] :=>+ '[ "a" ::: 'NoDef :=> 'Null 'PGint4+ , "b" ::: 'NoDef :=> 'Null 'PGfloat4 ]+:}++>>> :{+let+ setup :: Definition (Public '[]) (Public '["tab" ::: 'Table Table])+ setup = createTable #tab+ (nullable int `as` #a :* nullable real `as` #b) Nil+in printSQL setup+:}+CREATE TABLE "tab" ("a" int NULL, "b" real NULL);+-}+createTable+ :: ( KnownSymbol sch+ , KnownSymbol tab+ , columns ~ (col ': cols)+ , SOP.SListI columns+ , SOP.SListI constraints+ , Has sch db0 schema0+ , db1 ~ Alter sch (Create tab ('Table (constraints :=> columns)) schema0) db0 )+ => QualifiedAlias sch tab -- ^ the name of the table to add+ -> NP (Aliased (ColumnTypeExpression db0)) columns+ -- ^ the names and datatype of each column+ -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints+ -- ^ constraints that must hold for the table+ -> Definition db0 db1+createTable tab columns constraints = UnsafeDefinition $+ "CREATE TABLE" <+> renderCreation tab columns constraints++{-| `createTableIfNotExists` creates a table if it doesn't exist, but does not add it to the schema.+Instead, the schema already has the table so if the table did not yet exist, the schema was wrong.+`createTableIfNotExists` fixes this. Interestingly, this property makes it an idempotent in+the `Control.Category.Category` of `Definition`s.++>>> :set -XOverloadedLabels -XTypeApplications+>>> :{+type Table = '[] :=>+ '[ "a" ::: 'NoDef :=> 'Null 'PGint4+ , "b" ::: 'NoDef :=> 'Null 'PGfloat4 ]+:}++>>> type Schemas = Public '["tab" ::: 'Table Table]++>>> :{+let+ setup :: Definition Schemas Schemas+ setup = createTableIfNotExists #tab+ (nullable int `as` #a :* nullable real `as` #b) Nil+in printSQL setup+:}+CREATE TABLE IF NOT EXISTS "tab" ("a" int NULL, "b" real NULL);+-}+createTableIfNotExists+ :: ( KnownSymbol sch+ , KnownSymbol tab+ , columns ~ (col ': cols)+ , SOP.SListI columns+ , SOP.SListI constraints+ , Has sch db0 schema0+ , db1 ~ Alter sch (CreateIfNotExists tab ('Table (constraints :=> columns)) schema0) db0 )+ => QualifiedAlias sch tab -- ^ the name of the table to add+ -> NP (Aliased (ColumnTypeExpression db0)) columns+ -- ^ the names and datatype of each column+ -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints+ -- ^ constraints that must hold for the table+ -> Definition db0 db1+createTableIfNotExists tab columns constraints = UnsafeDefinition $+ "CREATE TABLE IF NOT EXISTS"+ <+> renderCreation tab columns constraints++-- helper function for `createTable` and `createTableIfNotExists`+renderCreation+ :: ( KnownSymbol sch+ , KnownSymbol tab+ , SOP.SListI columns+ , SOP.SListI constraints )+ => QualifiedAlias sch tab -- ^ the name of the table to add+ -> NP (Aliased (ColumnTypeExpression db0)) columns+ -- ^ the names and datatype of each column+ -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints+ -- ^ constraints that must hold for the table+ -> ByteString+renderCreation tab columns constraints = renderSQL tab+ <+> parenthesized+ ( renderCommaSeparated renderColumnDef columns+ <> ( case constraints of+ Nil -> ""+ _ -> ", " <>+ renderCommaSeparated renderConstraint constraints ) )+ <> ";"+ where+ renderColumnDef :: Aliased (ColumnTypeExpression db) x -> ByteString+ renderColumnDef (ty `As` column) =+ renderSQL column <+> renderColumnTypeExpression ty+ renderConstraint+ :: Aliased (TableConstraintExpression sch tab db) constraint+ -> ByteString+ renderConstraint (constraint `As` alias) =+ "CONSTRAINT" <+> renderSQL alias <+> renderSQL constraint++-- | `dropTable` removes a table from the schema.+--+-- >>> :{+-- let+-- definition :: Definition '["public" ::: '["muh_table" ::: 'Table t]] (Public '[])+-- definition = dropTable #muh_table+-- :}+--+-- >>> printSQL definition+-- DROP TABLE "muh_table";+dropTable+ :: ( Has sch db schema+ , KnownSymbol tab )+ => QualifiedAlias sch tab -- ^ table to remove+ -> Definition db (Alter sch (DropSchemum tab 'Table schema) db)+dropTable tab = UnsafeDefinition $ "DROP TABLE" <+> renderSQL tab <> ";"++-- | Drop a table if it exists.+dropTableIfExists+ :: ( Has sch db schema+ , KnownSymbol tab)+ => QualifiedAlias sch tab -- ^ table to remove+ -> Definition db (Alter sch (DropSchemumIfExists tab 'Table schema) db)+dropTableIfExists tab = UnsafeDefinition $+ "DROP TABLE IF EXISTS" <+> renderSQL tab <> ";"++-- | `alterTable` changes the definition of a table from the schema.+alterTable+ :: (Has sch db schema, KnownSymbol tab)+ => QualifiedAlias sch tab -- ^ table to alter+ -> AlterTable sch tab db table -- ^ alteration to perform+ -> Definition db (Alter sch (Alter tab ('Table table) schema) db)+alterTable tab alteration = UnsafeDefinition $+ "ALTER TABLE"+ <+> renderSQL tab+ <+> renderAlterTable alteration+ <> ";"++-- | `alterTable` changes the definition of a table from the schema.+alterTableIfExists+ :: (Has sch db schema, KnownSymbol tab)+ => QualifiedAlias sch tab -- ^ table to alter+ -> AlterTable sch tab db table -- ^ alteration to perform+ -> Definition db (Alter sch (AlterIfExists tab ('Table table) schema) db)+alterTableIfExists tab alteration = UnsafeDefinition $+ "ALTER TABLE IF EXISTS"+ <+> renderSQL tab+ <+> renderAlterTable alteration+ <> ";"++-- | `alterTableRename` changes the name of a table from the schema.+--+-- >>> printSQL $ alterTableRename #foo #bar+-- ALTER TABLE "foo" RENAME TO "bar";+alterTableRename+ :: (KnownSymbol tab0, KnownSymbol tab1)+ => Alias tab0 -- ^ table to rename+ -> Alias tab1 -- ^ what to rename it+ -> Definition schema (Rename tab0 tab1 schema)+alterTableRename tab0 tab1 = UnsafeDefinition $+ "ALTER TABLE" <+> renderSQL tab0+ <+> "RENAME TO" <+> renderSQL tab1 <> ";"++-- | Rename a table if it exists.+alterTableIfExistsRename+ :: (KnownSymbol tab0, KnownSymbol tab1)+ => Alias tab0 -- ^ table to rename+ -> Alias tab1 -- ^ what to rename it+ -> Definition schema (RenameIfExists tab0 tab1 schema)+alterTableIfExistsRename tab0 tab1 = UnsafeDefinition $+ "ALTER TABLE IF EXISTS" <+> renderSQL tab0+ <+> "RENAME TO" <+> renderSQL tab1 <> ";"++-- | An `AlterTable` describes the alteration to perform on the columns+-- of a table.+newtype AlterTable+ (sch :: Symbol)+ (tab :: Symbol)+ (db :: SchemasType)+ (table :: TableType) =+ UnsafeAlterTable {renderAlterTable :: ByteString}+ deriving (GHC.Generic,Show,Eq,Ord,NFData)++-- | An `addConstraint` adds a table constraint.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('["positive" ::: 'Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- definition = alterTable #tab (addConstraint #positive (check #col (#col .> 0)))+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" ADD CONSTRAINT "positive" CHECK (("col" > (0 :: int4)));+addConstraint+ :: ( KnownSymbol alias+ , Has sch db schema+ , Has tab schema ('Table (constraints :=> columns)) )+ => Alias alias+ -> TableConstraintExpression sch tab db constraint+ -- ^ constraint to add+ -> AlterTable sch tab db (Create alias constraint constraints :=> columns)+addConstraint alias constraint = UnsafeAlterTable $+ "ADD" <+> "CONSTRAINT" <+> renderSQL alias+ <+> renderSQL constraint++-- | A `dropConstraint` drops a table constraint.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- definition = alterTable #tab (dropConstraint #positive)+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" DROP CONSTRAINT "positive";+dropConstraint+ :: ( KnownSymbol constraint+ , Has sch db schema+ , Has tab schema ('Table (constraints :=> columns)) )+ => Alias constraint+ -- ^ constraint to drop+ -> AlterTable sch tab db (Drop constraint constraints :=> columns)+dropConstraint constraint = UnsafeAlterTable $+ "DROP" <+> "CONSTRAINT" <+> renderSQL constraint++-- | An `AddColumn` is either @NULL@ or has @DEFAULT@.+class AddColumn ty where+ -- | `addColumn` adds a new column, initially filled with whatever+ -- default value is given or with @NULL@.+ --+ -- >>> :{+ -- let+ -- definition :: Definition+ -- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]+ -- '["public" ::: '["tab" ::: 'Table ('[] :=>+ -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4+ -- , "col2" ::: 'Def :=> 'Null 'PGtext ])]]+ -- definition = alterTable #tab (addColumn #col2 (text & nullable & default_ "foo"))+ -- in printSQL definition+ -- :}+ -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL DEFAULT (E'foo' :: text);+ --+ -- >>> :{+ -- let+ -- definition :: Definition+ -- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]+ -- '["public" ::: '["tab" ::: 'Table ('[] :=>+ -- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4+ -- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]]+ -- definition = alterTable #tab (addColumn #col2 (text & nullable))+ -- in printSQL definition+ -- :}+ -- ALTER TABLE "tab" ADD COLUMN "col2" text NULL;+ addColumn+ :: ( KnownSymbol column+ , Has sch db schema+ , Has tab schema ('Table (constraints :=> columns)) )+ => Alias column -- ^ column to add+ -> ColumnTypeExpression db ty -- ^ type of the new column+ -> AlterTable sch tab db (constraints :=> Create column ty columns)+ addColumn column ty = UnsafeAlterTable $+ "ADD COLUMN" <+> renderSQL column <+> renderColumnTypeExpression ty+instance {-# OVERLAPPING #-} AddColumn ('Def :=> ty)+instance {-# OVERLAPPABLE #-} AddColumn ('NoDef :=> 'Null ty)++-- | A `dropColumn` removes a column. Whatever data was in the column+-- disappears. Table constraints involving the column are dropped, too.+-- However, if the column is referenced by a foreign key constraint of+-- another table, PostgreSQL will not silently drop that constraint.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=>+-- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4+-- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]+-- definition = alterTable #tab (dropColumn #col2)+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" DROP COLUMN "col2";+dropColumn+ :: ( KnownSymbol column+ , Has sch db schema+ , Has tab schema ('Table (constraints :=> columns)) )+ => Alias column -- ^ column to remove+ -> AlterTable sch tab db (constraints :=> Drop column columns)+dropColumn column = UnsafeAlterTable $+ "DROP COLUMN" <+> renderSQL column++-- | A `renameColumn` renames a column.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["foo" ::: 'NoDef :=> 'Null 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["bar" ::: 'NoDef :=> 'Null 'PGint4])]]+-- definition = alterTable #tab (renameColumn #foo #bar)+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" RENAME COLUMN "foo" TO "bar";+renameColumn+ :: ( KnownSymbol column0+ , KnownSymbol column1+ , Has sch db schema+ , Has tab schema ('Table (constraints :=> columns)) )+ => Alias column0 -- ^ column to rename+ -> Alias column1 -- ^ what to rename the column+ -> AlterTable sch tab db (constraints :=> Rename column0 column1 columns)+renameColumn column0 column1 = UnsafeAlterTable $+ "RENAME COLUMN" <+> renderSQL column0 <+> "TO" <+> renderSQL column1++-- | An `alterColumn` alters a single column.+alterColumn+ :: ( KnownSymbol column+ , Has sch db schema+ , Has tab schema ('Table (constraints :=> columns))+ , Has column columns ty0 )+ => Alias column -- ^ column to alter+ -> AlterColumn db ty0 ty1 -- ^ alteration to perform+ -> AlterTable sch tab db (constraints :=> Alter column ty1 columns)+alterColumn column alteration = UnsafeAlterTable $+ "ALTER COLUMN" <+> renderSQL column <+> renderAlterColumn alteration++-- | An `AlterColumn` describes the alteration to perform on a single column.+newtype AlterColumn (db :: SchemasType) (ty0 :: ColumnType) (ty1 :: ColumnType) =+ UnsafeAlterColumn {renderAlterColumn :: ByteString}+ deriving (GHC.Generic,Show,Eq,Ord,NFData)++-- | A `setDefault` sets a new default for a column. Note that this doesn't+-- affect any existing rows in the table, it just changes the default for+-- future insert and update commands.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]]+-- definition = alterTable #tab (alterColumn #col (setDefault 5))+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" ALTER COLUMN "col" SET DEFAULT (5 :: int4);+setDefault+ :: Expression 'Ungrouped '[] '[] db '[] '[] ty -- ^ default value to set+ -> AlterColumn db (constraint :=> ty) ('Def :=> ty)+setDefault expression = UnsafeAlterColumn $+ "SET DEFAULT" <+> renderExpression expression++-- | A `dropDefault` removes any default value for a column.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'Def :=> 'Null 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]+-- definition = alterTable #tab (alterColumn #col dropDefault)+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" ALTER COLUMN "col" DROP DEFAULT;+dropDefault :: AlterColumn db ('Def :=> ty) ('NoDef :=> ty)+dropDefault = UnsafeAlterColumn $ "DROP DEFAULT"++-- | A `setNotNull` adds a @NOT NULL@ constraint to a column.+-- The constraint will be checked immediately, so the table data must satisfy+-- the constraint before it can be added.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- definition = alterTable #tab (alterColumn #col setNotNull)+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" ALTER COLUMN "col" SET NOT NULL;+setNotNull+ :: AlterColumn db (constraint :=> 'Null ty) (constraint :=> 'NotNull ty)+setNotNull = UnsafeAlterColumn $ "SET NOT NULL"++-- | A `dropNotNull` drops a @NOT NULL@ constraint from a column.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])]]+-- definition = alterTable #tab (alterColumn #col dropNotNull)+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" ALTER COLUMN "col" DROP NOT NULL;+dropNotNull+ :: AlterColumn db (constraint :=> 'NotNull ty) (constraint :=> 'Null ty)+dropNotNull = UnsafeAlterColumn $ "DROP NOT NULL"++-- | An `alterType` converts a column to a different data type.+-- This will succeed only if each existing entry in the column can be+-- converted to the new type by an implicit cast.+--+-- >>> :{+-- let+-- definition :: Definition+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]+-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGnumeric])]]+-- definition =+-- alterTable #tab (alterColumn #col (alterType (numeric & notNullable)))+-- in printSQL definition+-- :}+-- ALTER TABLE "tab" ALTER COLUMN "col" TYPE numeric NOT NULL;+alterType :: ColumnTypeExpression db ty -> AlterColumn db ty0 ty+alterType ty = UnsafeAlterColumn $ "TYPE" <+> renderColumnTypeExpression ty
+ src/Squeal/PostgreSQL/Definition/Type.hs view
@@ -0,0 +1,247 @@+{-|+Module: Squeal.PostgreSQL.Definition.Type+Description: create and drop types+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++create and drop types+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.Type+ ( -- * Create+ createTypeEnum+ , createTypeEnumFrom+ , createTypeComposite+ , createTypeCompositeFrom+ , createTypeRange+ , createDomain+ -- * Drop+ , dropType+ , dropTypeIfExists+ ) where++import Data.ByteString+import Data.Monoid+import GHC.TypeLits+import Prelude hiding ((.), id)++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Expression.Type+import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.PG+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL+-- >>> import qualified GHC.Generics as GHC+-- >>> import qualified Generics.SOP as SOP++-- | Enumerated types are created using the `createTypeEnum` command, for example+--+-- >>> printSQL $ (createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy") :: Definition (Public '[]) '["public" ::: '["mood" ::: 'Typedef ('PGenum '["sad","ok","happy"])]])+-- CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');+createTypeEnum+ :: (KnownSymbol enum, Has sch db schema, SOP.All KnownSymbol labels)+ => QualifiedAlias sch enum+ -- ^ name of the user defined enumerated type+ -> NP PGlabel labels+ -- ^ labels of the enumerated type+ -> Definition db (Alter sch (Create enum ('Typedef ('PGenum labels)) schema) db)+createTypeEnum enum labels = UnsafeDefinition $+ "CREATE" <+> "TYPE" <+> renderSQL enum <+> "AS" <+> "ENUM" <+>+ parenthesized (renderSQL labels) <> ";"++-- | Enumerated types can also be generated from a Haskell type, for example+--+-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic+-- >>> instance SOP.Generic Schwarma+-- >>> instance SOP.HasDatatypeInfo Schwarma+-- >>> :{+-- let+-- createSchwarma :: Definition (Public '[]) '["public" ::: '["schwarma" ::: 'Typedef (PG (Enumerated Schwarma))]]+-- createSchwarma = createTypeEnumFrom @Schwarma #schwarma+-- in+-- printSQL createSchwarma+-- :}+-- CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');+createTypeEnumFrom+ :: forall hask sch enum db schema.+ ( SOP.Generic hask+ , SOP.All KnownSymbol (LabelsPG hask)+ , KnownSymbol enum+ , Has sch db schema )+ => QualifiedAlias sch enum+ -- ^ name of the user defined enumerated type+ -> Definition db (Alter sch (Create enum ('Typedef (PG (Enumerated hask))) schema) db)+createTypeEnumFrom enum = createTypeEnum enum+ (SOP.hpure label :: NP PGlabel (LabelsPG hask))++{- | `createTypeComposite` creates a composite type. The composite type is+specified by a list of attribute names and data types.++>>> :{+type PGcomplex = 'PGcomposite+ '[ "real" ::: 'NotNull 'PGfloat8+ , "imaginary" ::: 'NotNull 'PGfloat8 ]+:}++>>> :{+let+ setup :: Definition (Public '[]) '["public" ::: '["complex" ::: 'Typedef PGcomplex]]+ setup = createTypeComposite #complex+ (float8 `as` #real :* float8 `as` #imaginary)+in printSQL setup+:}+CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);+-}+createTypeComposite+ :: (KnownSymbol ty, Has sch db schema, SOP.SListI fields)+ => QualifiedAlias sch ty+ -- ^ name of the user defined composite type+ -> NP (Aliased (TypeExpression db)) fields+ -- ^ list of attribute names and data types+ -> Definition db (Alter sch (Create ty ('Typedef ('PGcomposite fields)) schema) db)+createTypeComposite ty fields = UnsafeDefinition $+ "CREATE" <+> "TYPE" <+> renderSQL ty <+> "AS" <+> parenthesized+ (renderCommaSeparated renderField fields) <> ";"+ where+ renderField :: Aliased (TypeExpression db) x -> ByteString+ renderField (typ `As` alias) =+ renderSQL alias <+> renderSQL typ++-- | Composite types can also be generated from a Haskell type, for example+--+-- >>> data Complex = Complex {real :: Double, imaginary :: Double} deriving GHC.Generic+-- >>> instance SOP.Generic Complex+-- >>> instance SOP.HasDatatypeInfo Complex+-- >>> type Schema = '["complex" ::: 'Typedef (PG (Composite Complex))]+-- >>> :{+-- let+-- createComplex :: Definition (Public '[]) (Public Schema)+-- createComplex = createTypeCompositeFrom @Complex #complex+-- in+-- printSQL createComplex+-- :}+-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);+createTypeCompositeFrom+ :: forall hask sch ty db schema.+ ( SOP.All (FieldTyped db) (RowPG hask)+ , KnownSymbol ty+ , Has sch db schema )+ => QualifiedAlias sch ty+ -- ^ name of the user defined composite type+ -> Definition db (Alter sch (Create ty ( 'Typedef (PG (Composite hask))) schema) db)+createTypeCompositeFrom ty = createTypeComposite ty+ (SOP.hcpure (SOP.Proxy :: SOP.Proxy (FieldTyped db)) fieldtype+ :: NP (Aliased (TypeExpression db)) (RowPG hask))++{-|+`createDomain` creates a new domain. A domain is essentially a data type+with constraints (restrictions on the allowed set of values).++Domains are useful for abstracting common constraints on fields+into a single location for maintenance. For example, several tables might+contain email address columns, all requiring the same+`Squeal.PostgreSQL.Definition.Table.Constraint.check` constraint+to verify the address syntax. Define a domain rather than setting up+each table's constraint individually.++>>> :{+let+ createPositive :: Definition (Public '[]) (Public '["positive" ::: 'Typedef 'PGfloat4])+ createPositive = createDomain #positive real (#value .> 0)+in printSQL createPositive+:}+CREATE DOMAIN "positive" AS real CHECK (("value" > (0.0 :: float4)));+-}+createDomain+ :: (Has sch db schema, KnownSymbol dom)+ => QualifiedAlias sch dom -- ^ domain alias+ -> (forall null. TypeExpression db (null ty)) -- ^ underlying type+ -> (forall tab. Condition 'Ungrouped '[] '[] db '[] '[tab ::: '["value" ::: 'Null ty]])+ -- ^ constraint on type+ -> Definition db (Alter sch (Create dom ('Typedef ty) schema) db)+createDomain dom ty condition =+ UnsafeDefinition $ "CREATE DOMAIN" <+> renderSQL dom+ <+> "AS" <+> renderTypeExpression ty+ <+> "CHECK" <+> parenthesized (renderSQL condition) <> ";"++{- | Range types are data types representing a range of values+of some element type (called the range's subtype).+The subtype must have a total order so that it is well-defined+whether element values are within, before, or after a range of values.++Range types are useful because they represent many element values+in a single range value, and because concepts such as overlapping ranges+can be expressed clearly.+The use of time and date ranges for scheduling purposes+is the clearest example; but price ranges,+measurement ranges from an instrument, and so forth can also be useful.++>>> :{+let+ createSmallIntRange :: Definition (Public '[]) (Public '["int2range" ::: 'Typedef ('PGrange 'PGint2)])+ createSmallIntRange = createTypeRange #int2range int2+in printSQL createSmallIntRange+:}+CREATE TYPE "int2range" AS RANGE (subtype = int2);+-}+createTypeRange+ :: (Has sch db schema, KnownSymbol range)+ => QualifiedAlias sch range -- ^ range alias+ -> (forall null. TypeExpression db (null ty)) -- ^ underlying type+ -> Definition db (Alter sch (Create range ('Typedef ('PGrange ty)) schema) db)+createTypeRange range ty = UnsafeDefinition $+ "CREATE" <+> "TYPE" <+> renderSQL range <+> "AS" <+> "RANGE" <+>+ parenthesized ("subtype" <+> "=" <+> renderTypeExpression ty) <> ";"++-- | Drop a type.+--+-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic+-- >>> instance SOP.Generic Schwarma+-- >>> instance SOP.HasDatatypeInfo Schwarma+-- >>> printSQL (dropType #schwarma :: Definition '["public" ::: '["schwarma" ::: 'Typedef (PG (Enumerated Schwarma))]] (Public '[]))+-- DROP TYPE "schwarma";+dropType+ :: (Has sch db schema, KnownSymbol td)+ => QualifiedAlias sch td+ -- ^ name of the user defined type+ -> Definition db (Alter sch (DropSchemum td 'Typedef schema) db)+dropType tydef = UnsafeDefinition $ "DROP TYPE" <+> renderSQL tydef <> ";"++-- | Drop a type if it exists.+dropTypeIfExists+ :: (Has sch db schema, KnownSymbol td)+ => QualifiedAlias sch td+ -- ^ name of the user defined type+ -> Definition db (Alter sch (DropSchemumIfExists td 'Typedef schema) db)+dropTypeIfExists tydef = UnsafeDefinition $+ "DROP TYPE IF EXISTS" <+> renderSQL tydef <> ";"
+ src/Squeal/PostgreSQL/Definition/View.hs view
@@ -0,0 +1,135 @@+{-|+Module: Squeal.PostgreSQL.Definition.View+Description: create and drop views+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++create and drop views+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeInType+ , TypeOperators+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Definition.View+ ( -- * Create+ createView+ , createOrReplaceView+ -- * Drop+ , dropView+ , dropViewIfExists+ ) where++import GHC.TypeLits++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{- | Create a view.++>>> type ABC = '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4]+>>> type BC = '["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4]+>>> :{+let+ definition :: Definition+ '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC)]]+ '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC), "bc" ::: 'View BC]]+ definition =+ createView #bc (select_ (#b :* #c) (from (table #abc)))+in printSQL definition+:}+CREATE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";+-}+createView+ :: (Has sch db schema, KnownSymbol vw)+ => QualifiedAlias sch vw -- ^ the name of the view to add+ -> Query '[] '[] db '[] view -- ^ query+ -> Definition db (Alter sch (Create vw ('View view) schema) db)+createView alias query = UnsafeDefinition $+ "CREATE" <+> "VIEW" <+> renderSQL alias <+> "AS"+ <+> renderQuery query <> ";"++{- | Create or replace a view.++>>> type ABC = '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4]+>>> type BC = '["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4]+>>> :{+let+ definition :: Definition+ '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC)]]+ '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC), "bc" ::: 'View BC]]+ definition =+ createOrReplaceView #bc (select_ (#b :* #c) (from (table #abc)))+in printSQL definition+:}+CREATE OR REPLACE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";+-}+createOrReplaceView+ :: (Has sch db schema, KnownSymbol vw)+ => QualifiedAlias sch vw -- ^ the name of the view to add+ -> Query '[] '[] db '[] view -- ^ query+ -> Definition db (Alter sch (CreateOrReplace vw ('View view) schema) db)+createOrReplaceView alias query = UnsafeDefinition $+ "CREATE OR REPLACE VIEW" <+> renderSQL alias <+> "AS"+ <+> renderQuery query <> ";"++-- | Drop a view.+--+-- >>> :{+-- let+-- definition :: Definition+-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])+-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]]+-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]]+-- definition = dropView #bc+-- in printSQL definition+-- :}+-- DROP VIEW "bc";+dropView+ :: (Has sch db schema, KnownSymbol vw)+ => QualifiedAlias sch vw -- ^ view to remove+ -> Definition db (Alter sch (DropSchemum vw 'View schema) db)+dropView vw = UnsafeDefinition $ "DROP VIEW" <+> renderSQL vw <> ";"++-- | Drop a view if it exists.+--+-- >>> :{+-- let+-- definition :: Definition+-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])+-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]]+-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]]+-- definition = dropViewIfExists #bc+-- in printSQL definition+-- :}+-- DROP VIEW IF EXISTS "bc";+dropViewIfExists+ :: (Has sch db schema, KnownSymbol vw)+ => QualifiedAlias sch vw -- ^ view to remove+ -> Definition db (Alter sch (DropIfExists vw schema) db)+dropViewIfExists vw = UnsafeDefinition $+ "DROP VIEW IF EXISTS" <+> renderSQL vw <> ";"
src/Squeal/PostgreSQL/Expression.hs view
@@ -1,17 +1,18 @@ {-| Module: Squeal.PostgreSQL.Expression-Description: Squeal expressions+Description: expressions Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Squeal expressions are the atoms used to build statements.+Expressions are the atoms used to build statements. -} {-# LANGUAGE AllowAmbiguousTypes , ConstraintKinds , DeriveGeneric+ , DerivingStrategies , FlexibleContexts , FlexibleInstances , FunctionalDependencies@@ -34,26 +35,37 @@ ( -- * Expression Expression (..) , Expr- , (:-->)+ -- * Function+ , type (-->)+ , Fun , unsafeFunction- , unsafeUnaryOpL- , unsafeUnaryOpR+ , function+ , unsafeLeftOp+ , unsafeRightOp+ -- * Operator , Operator+ , OperatorDB , unsafeBinaryOp+ , PGSubset (..)+ , PGIntersect (..)+ -- * Multivariable Function , FunctionVar , unsafeFunctionVar- , FunctionN+ , type (--->)+ , FunN , unsafeFunctionN- , PGSubset (..)+ , functionN -- * Re-export , (&)- , K (..)- , unK ) where import Control.Category import Control.DeepSeq+import Data.Binary.Builder (toLazyByteString) import Data.ByteString (ByteString)+import Data.ByteString.Builder (doubleDec, floatDec, int16Dec, int32Dec, int64Dec)+import Data.ByteString.Builder.Scientific (scientificBuilder)+import Data.ByteString.Lazy (toStrict) import Data.Function ((&)) import Data.Semigroup hiding (All) import Data.String@@ -65,10 +77,10 @@ import qualified GHC.Generics as GHC -import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.List+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -80,9 +92,10 @@ {- | `Expression`s are used in a variety of contexts, such as in the target `Squeal.PostgreSQL.Query.List` of the `Squeal.PostgreSQL.Query.select` command,-as new column values in `Squeal.PostgreSQL.Manipulation.insertRow` or+as new column values in `Squeal.PostgreSQL.Manipulation.insertInto` or `Squeal.PostgreSQL.Manipulation.update`,-or in search `Squeal.PostgreSQL.Logic.Condition`s in a number of commands.+or in search `Squeal.PostgreSQL.Expression.Logic.Condition`s+in a number of commands. The expression syntax allows the calculation of values from primitive expression using arithmetic, logical,@@ -90,29 +103,30 @@ The type parameters of `Expression` are -* @outer :: @ `FromType`, the @from@ clauses of any outer queries in which+* @lat :: @ `FromType`, the @from@ clauses of any lat queries in which the `Expression` is a correlated subquery expression;-* @commons :: @ `FromType`, the `Squeal.PostgreSQL.Query.CommonTableExpression`s+* @with :: @ `FromType`, the `Squeal.PostgreSQL.Query.CommonTableExpression`s that are in scope for the `Expression`; * @grp :: @ `Grouping`, the `Grouping` of the @from@ clause which may limit which columns may be referenced by alias;-* @schemas :: @ `SchemasType`, the schemas of your database that are in+* @db :: @ `SchemasType`, the schemas of your database that are in scope for the `Expression`; * @from :: @ `FromType`, the @from@ clause which the `Expression` may use to reference columns by alias;-* @ty :: @ `NullityType`, the type of the `Expression`.+* @ty :: @ `NullType`, the type of the `Expression`. -} newtype Expression- (outer :: FromType)- (commons :: FromType) (grp :: Grouping)- (schemas :: SchemasType)- (params :: [NullityType])+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType]) (from :: FromType)- (ty :: NullityType)+ (ty :: NullType) = UnsafeExpression { renderExpression :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL (Expression outer commons grp schemas params from ty) where+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (Expression grp lat with db params from ty) where renderSQL = renderExpression -- | An `Expr` is a closed `Expression`.@@ -122,30 +136,43 @@ -- or alias references. It can be used as -- a simple piece of more complex `Expression`s. type Expr x- = forall outer commons grp schemas params from- . Expression outer commons grp schemas params from x+ = forall grp lat with db params from+ . Expression grp lat with db params from x -- ^ cannot reference aliases -- | A @RankNType@ for binary operators. type Operator x1 x2 y- = forall outer commons grp schemas params from- . Expression outer commons grp schemas params from x1+ = forall grp lat with db params from+ . Expression grp lat with db params from x1 -- ^ left input- -> Expression outer commons grp schemas params from x2+ -> Expression grp lat with db params from x2 -- ^ right input- -> Expression outer commons grp schemas params from y+ -> Expression grp lat with db params from y -- ^ output +-- | Like `Operator` but depends on the schemas of the database+type OperatorDB db x1 x2 y+ = forall grp lat with params from+ . Expression grp lat with db params from x1+ -- ^ left input+ -> Expression grp lat with db params from x2+ -- ^ right input+ -> Expression grp lat with db params from y+ -- ^ output+ -- | A @RankNType@ for functions with a single argument. -- These could be either function calls or unary operators. -- This is a subtype of the usual Haskell function type `Prelude.->`, -- indeed a subcategory as it is closed under the usual -- `Prelude..` and `Prelude.id`.-type (:-->) x y- = forall outer commons grp schemas params from- . Expression outer commons grp schemas params from x+type (-->) x y = forall db. Fun db x y++-- | Like `-->` but depends on the schemas of the database+type Fun db x y+ = forall grp lat with params from+ . Expression grp lat with db params from x -- ^ input- -> Expression outer commons grp schemas params from y+ -> Expression grp lat with db params from y -- ^ output {- | A @RankNType@ for functions with a fixed-length list of heterogeneous arguments.@@ -154,23 +181,26 @@ >>> printSQL (unsafeFunctionN "fun" (true :* false :* localTime *: true)) fun(TRUE, FALSE, LOCALTIME, TRUE) -}-type FunctionN xs y- = forall outer commons grp schemas params from- . NP (Expression outer commons grp schemas params from) xs+type (--->) xs y = forall db. FunN db xs y++-- | Like `--->` but depends on the schemas of the database+type FunN db xs y+ = forall grp lat with params from+ . NP (Expression grp lat with db params from) xs -- ^ inputs- -> Expression outer commons grp schemas params from y+ -> Expression grp lat with db params from y -- ^ output {- | A @RankNType@ for functions with a variable-length list of homogeneous arguments and at least 1 more argument. -} type FunctionVar x0 x1 y- = forall outer commons grp schemas params from- . [Expression outer commons grp schemas params from x0]+ = forall grp lat with db params from+ . [Expression grp lat with db params from x0] -- ^ inputs- -> Expression outer commons grp schemas params from x1+ -> Expression grp lat with db params from x1 -- ^ must have at least 1 input- -> Expression outer commons grp schemas params from y+ -> Expression grp lat with db params from y -- ^ output {- | >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false)@@ -180,104 +210,104 @@ unsafeFunctionVar fun xs x = UnsafeExpression $ fun <> parenthesized (commaSeparated (renderSQL <$> xs) <> ", " <> renderSQL x) -instance (HasUnique tab (Join outer from) row, Has col row ty)- => IsLabel col (Expression outer commons 'Ungrouped schemas params from ty) where+instance (HasUnique tab (Join lat from) row, Has col row ty)+ => IsLabel col (Expression 'Ungrouped lat with db params from ty) where fromLabel = UnsafeExpression $ renderSQL (Alias @col)-instance (HasUnique tab (Join outer from) row, Has col row ty, tys ~ '[ty])- => IsLabel col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where+instance (HasUnique tab (Join lat from) row, Has col row ty, tys ~ '[ty])+ => IsLabel col (NP (Expression 'Ungrouped lat with db params from) tys) where fromLabel = fromLabel @col :* Nil-instance (HasUnique tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))+instance (HasUnique tab (Join lat from) row, Has col row ty, column ~ (col ::: ty)) => IsLabel col- (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where+ (Aliased (Expression 'Ungrouped lat with db params from) column) where fromLabel = fromLabel @col `As` Alias-instance (HasUnique tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])+instance (HasUnique tab (Join lat from) row, Has col row ty, columns ~ '[col ::: ty]) => IsLabel col- (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where+ (NP (Aliased (Expression 'Ungrouped lat with db params from)) columns) where fromLabel = fromLabel @col :* Nil -instance (Has tab (Join outer from) row, Has col row ty)- => IsQualified tab col (Expression outer commons 'Ungrouped schemas params from ty) where+instance (Has tab (Join lat from) row, Has col row ty)+ => IsQualified tab col (Expression 'Ungrouped lat with db params from ty) where tab ! col = UnsafeExpression $ renderSQL tab <> "." <> renderSQL col-instance (Has tab (Join outer from) row, Has col row ty, tys ~ '[ty])- => IsQualified tab col (NP (Expression outer commons 'Ungrouped schemas params from) tys) where+instance (Has tab (Join lat from) row, Has col row ty, tys ~ '[ty])+ => IsQualified tab col (NP (Expression 'Ungrouped lat with db params from) tys) where tab ! col = tab ! col :* Nil-instance (Has tab (Join outer from) row, Has col row ty, column ~ (col ::: ty))+instance (Has tab (Join lat from) row, Has col row ty, column ~ (col ::: ty)) => IsQualified tab col- (Aliased (Expression outer commons 'Ungrouped schemas params from) column) where+ (Aliased (Expression 'Ungrouped lat with db params from) column) where tab ! col = tab ! col `As` col-instance (Has tab (Join outer from) row, Has col row ty, columns ~ '[col ::: ty])+instance (Has tab (Join lat from) row, Has col row ty, columns ~ '[col ::: ty]) => IsQualified tab col- (NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns) where+ (NP (Aliased (Expression 'Ungrouped lat with db params from)) columns) where tab ! col = tab ! col :* Nil instance- ( HasUnique tab (Join outer from) row+ ( HasUnique tab (Join lat from) row , Has col row ty , GroupedBy tab col bys ) => IsLabel col- (Expression outer commons ('Grouped bys) schemas params from ty) where+ (Expression ('Grouped bys) lat with db params from ty) where fromLabel = UnsafeExpression $ renderSQL (Alias @col) instance- ( HasUnique tab (Join outer from) row+ ( HasUnique tab (Join lat from) row , Has col row ty , GroupedBy tab col bys , tys ~ '[ty] ) => IsLabel col- (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where+ (NP (Expression ('Grouped bys) lat with db params from) tys) where fromLabel = fromLabel @col :* Nil instance- ( HasUnique tab (Join outer from) row+ ( HasUnique tab (Join lat from) row , Has col row ty , GroupedBy tab col bys , column ~ (col ::: ty) ) => IsLabel col- (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where+ (Aliased (Expression ('Grouped bys) lat with db params from) column) where fromLabel = fromLabel @col `As` Alias instance- ( HasUnique tab (Join outer from) row+ ( HasUnique tab (Join lat from) row , Has col row ty , GroupedBy tab col bys , columns ~ '[col ::: ty] ) => IsLabel col- (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where+ (NP (Aliased (Expression ('Grouped bys) lat with db params from)) columns) where fromLabel = fromLabel @col :* Nil instance- ( Has tab (Join outer from) row+ ( Has tab (Join lat from) row , Has col row ty , GroupedBy tab col bys ) => IsQualified tab col- (Expression outer commons ('Grouped bys) schemas params from ty) where+ (Expression ('Grouped bys) lat with db params from ty) where tab ! col = UnsafeExpression $ renderSQL tab <> "." <> renderSQL col instance- ( Has tab (Join outer from) row+ ( Has tab (Join lat from) row , Has col row ty , GroupedBy tab col bys , tys ~ '[ty] ) => IsQualified tab col- (NP (Expression outer commons ('Grouped bys) schemas params from) tys) where+ (NP (Expression ('Grouped bys) lat with db params from) tys) where tab ! col = tab ! col :* Nil instance- ( Has tab (Join outer from) row+ ( Has tab (Join lat from) row , Has col row ty , GroupedBy tab col bys , column ~ (col ::: ty) ) => IsQualified tab col- (Aliased (Expression outer commons ('Grouped bys) schemas params from) column) where+ (Aliased (Expression ('Grouped bys) lat with db params from) column) where tab ! col = tab ! col `As` col instance- ( Has tab (Join outer from) row+ ( Has tab (Join lat from) row , Has col row ty , GroupedBy tab col bys , columns ~ '[col ::: ty] ) => IsQualified tab col- (NP (Aliased (Expression outer commons ('Grouped bys) schemas params from)) columns) where+ (NP (Aliased (Expression ('Grouped bys) lat with db params from)) columns) where tab ! col = tab ! col :* Nil instance (KnownSymbol label, label `In` labels) => IsPGlabel label- (Expression outer commons grp schemas params from (null ('PGenum labels))) where+ (Expression grp lat with db params from (null ('PGenum labels))) where label = UnsafeExpression $ renderSQL (PGlabel @label) -- | >>> printSQL $ unsafeBinaryOp "OR" true false@@ -286,30 +316,70 @@ unsafeBinaryOp op x y = UnsafeExpression $ parenthesized $ renderSQL x <+> op <+> renderSQL y --- | >>> printSQL $ unsafeUnaryOpL "NOT" true+-- | >>> printSQL $ unsafeLeftOp "NOT" true -- (NOT TRUE)-unsafeUnaryOpL :: ByteString -> x :--> y-unsafeUnaryOpL op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x+unsafeLeftOp :: ByteString -> x --> y+unsafeLeftOp op x = UnsafeExpression $ parenthesized $ op <+> renderSQL x --- | >>> printSQL $ true & unsafeUnaryOpR "IS NOT TRUE"+-- | >>> printSQL $ true & unsafeRightOp "IS NOT TRUE" -- (TRUE IS NOT TRUE)-unsafeUnaryOpR :: ByteString -> x :--> y-unsafeUnaryOpR op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op+unsafeRightOp :: ByteString -> x --> y+unsafeRightOp op x = UnsafeExpression $ parenthesized $ renderSQL x <+> op -- | >>> printSQL $ unsafeFunction "f" true -- f(TRUE)-unsafeFunction :: ByteString -> x :--> y+unsafeFunction :: ByteString -> x --> y unsafeFunction fun x = UnsafeExpression $ fun <> parenthesized (renderSQL x) --- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a')--- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a')-unsafeFunctionN :: SListI xs => ByteString -> FunctionN xs y+{- | Call a user defined function of a single variable++>>> type Fn = '[ 'Null 'PGint4] :=> 'Returns ('NotNull 'PGnumeric)+>>> type Schema = '["fn" ::: 'Function Fn]+>>> :{+let+ fn :: Fun (Public Schema) ('Null 'PGint4) ('NotNull 'PGnumeric)+ fn = function #fn+in+ printSQL (fn 1)+:}+"fn"((1 :: int4))+-}+function+ :: (Has sch db schema, Has fun schema ('Function ('[x] :=> 'Returns y)))+ => QualifiedAlias sch fun -- ^ function name+ -> Fun db x y+function = unsafeFunction . renderSQL++-- | >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: inline 'a')+-- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, (E'a' :: char(1)))+unsafeFunctionN :: SListI xs => ByteString -> xs ---> y unsafeFunctionN fun xs = UnsafeExpression $ fun <> parenthesized (renderCommaSeparated renderSQL xs) -instance ty `In` PGNum- => Num (Expression outer commons grp schemas params from (null ty)) where+{- | Call a user defined multivariable function++>>> type Fn = '[ 'Null 'PGint4, 'Null 'PGbool] :=> 'Returns ('NotNull 'PGnumeric)+>>> type Schema = '["fn" ::: 'Function Fn]+>>> :{+let+ fn :: FunN (Public Schema) '[ 'Null 'PGint4, 'Null 'PGbool] ('NotNull 'PGnumeric)+ fn = functionN #fn+in+ printSQL (fn (1 *: true))+:}+"fn"((1 :: int4), TRUE)+-}+functionN+ :: ( Has sch db schema+ , Has fun schema ('Function (xs :=> 'Returns y))+ , SListI xs )+ => QualifiedAlias sch fun -- ^ function alias+ -> FunN db xs y+functionN = unsafeFunctionN . renderSQL++instance+ Num (Expression grp lat with db params from (null 'PGint2)) where (+) = unsafeBinaryOp "+" (-) = unsafeBinaryOp "-" (*) = unsafeBinaryOp "*"@@ -317,21 +387,143 @@ signum = unsafeFunction "sign" fromInteger = UnsafeExpression- . fromString- . show+ . parenthesized+ . (<> " :: int2")+ . toStrict+ . toLazyByteString+ . int16Dec+ . fromInteger+instance+ Num (Expression grp lat with db params from (null 'PGint4)) where+ (+) = unsafeBinaryOp "+"+ (-) = unsafeBinaryOp "-"+ (*) = unsafeBinaryOp "*"+ abs = unsafeFunction "abs"+ signum = unsafeFunction "sign"+ fromInteger+ = UnsafeExpression+ . parenthesized+ . (<> " :: int4")+ . toStrict+ . toLazyByteString+ . int32Dec+ . fromInteger+instance+ Num (Expression grp lat with db params from (null 'PGint8)) where+ (+) = unsafeBinaryOp "+"+ (-) = unsafeBinaryOp "-"+ (*) = unsafeBinaryOp "*"+ abs = unsafeFunction "abs"+ signum = unsafeFunction "sign"+ fromInteger x =+ let+ y = fromInteger x+ in+ if y == minBound+ -- For some reason Postgres throws an error with+ -- (-9223372036854775808 :: int8)+ -- even though it's a valid lowest value for int8+ then fromInteger (x+1) - 1+ else UnsafeExpression+ . parenthesized+ . (<> " :: int8")+ . toStrict+ . toLazyByteString+ $ int64Dec y+instance+ Num (Expression grp lat with db params from (null 'PGfloat4)) where+ (+) = unsafeBinaryOp "+"+ (-) = unsafeBinaryOp "-"+ (*) = unsafeBinaryOp "*"+ abs = unsafeFunction "abs"+ signum = unsafeFunction "sign"+ fromInteger x+ = UnsafeExpression+ . parenthesized+ . (<> " :: float4") $+ let+ y = fromInteger x+ decimal = toStrict . toLazyByteString . floatDec+ in+ if isNaN y || isInfinite y+ then singleQuotedUtf8 (decimal y)+ else decimal y+instance+ Num (Expression grp lat with db params from (null 'PGfloat8)) where+ (+) = unsafeBinaryOp "+"+ (-) = unsafeBinaryOp "-"+ (*) = unsafeBinaryOp "*"+ abs = unsafeFunction "abs"+ signum = unsafeFunction "sign"+ fromInteger x+ = UnsafeExpression+ . parenthesized+ . (<> " :: float8") $+ let+ y = fromInteger x+ decimal = toStrict . toLazyByteString . doubleDec+ in+ if isNaN y || isInfinite y+ then singleQuotedUtf8 (decimal y)+ else decimal y+instance+ Num (Expression grp lat with db params from (null 'PGnumeric)) where+ (+) = unsafeBinaryOp "+"+ (-) = unsafeBinaryOp "-"+ (*) = unsafeBinaryOp "*"+ abs = unsafeFunction "abs"+ signum = unsafeFunction "sign"+ fromInteger+ = UnsafeExpression+ . parenthesized+ . (<> " :: numeric")+ . toStrict+ . toLazyByteString+ . scientificBuilder+ . fromInteger -instance (ty `In` PGNum, ty `In` PGFloating) => Fractional- (Expression outer commons grp schemas params from (null ty)) where+instance Fractional+ (Expression grp lat with db params from (null 'PGfloat4)) where (/) = unsafeBinaryOp "/"+ fromRational x+ = UnsafeExpression+ . parenthesized+ . (<> " :: float4") $+ let+ y = fromRational x+ decimal = toStrict . toLazyByteString . floatDec+ in+ if isNaN y || isInfinite y+ then singleQuotedUtf8 (decimal y)+ else decimal y+instance Fractional+ (Expression grp lat with db params from (null 'PGfloat8)) where+ (/) = unsafeBinaryOp "/"+ fromRational x+ = UnsafeExpression+ . parenthesized+ . (<> " :: float8") $+ let+ y = fromRational x+ decimal = toStrict . toLazyByteString . doubleDec+ in+ if isNaN y || isInfinite y+ then singleQuotedUtf8 (decimal y)+ else decimal y+instance Fractional+ (Expression grp lat with db params from (null 'PGnumeric)) where+ (/) = unsafeBinaryOp "/" fromRational = UnsafeExpression- . fromString- . ($ "")- . showFFloat Nothing- . fromRat @Double+ . parenthesized+ . (<> " :: numeric")+ . toStrict+ . toLazyByteString+ . scientificBuilder+ . fromRational -instance (ty `In` PGNum, ty `In` PGFloating) => Floating- (Expression outer commons grp schemas params from (null ty)) where+instance Floating+ (Expression grp lat with db params from (null 'PGfloat4)) where pi = UnsafeExpression "pi()" exp = unsafeFunction "exp" log = unsafeFunction "ln"@@ -351,48 +543,107 @@ asinh x = log (x + sqrt (x*x + 1)) acosh x = log (x + sqrt (x*x - 1)) atanh x = log ((1 + x) / (1 - x)) / 2+instance Floating+ (Expression grp lat with db params from (null 'PGfloat8)) where+ pi = UnsafeExpression "pi()"+ exp = unsafeFunction "exp"+ log = unsafeFunction "ln"+ sqrt = unsafeFunction "sqrt"+ b ** x = UnsafeExpression $+ "power(" <> renderSQL b <> ", " <> renderSQL x <> ")"+ logBase b y = log y / log b+ sin = unsafeFunction "sin"+ cos = unsafeFunction "cos"+ tan = unsafeFunction "tan"+ asin = unsafeFunction "asin"+ acos = unsafeFunction "acos"+ atan = unsafeFunction "atan"+ sinh x = (exp x - exp (-x)) / 2+ cosh x = (exp x + exp (-x)) / 2+ tanh x = sinh x / cosh x+ asinh x = log (x + sqrt (x*x + 1))+ acosh x = log (x + sqrt (x*x - 1))+ atanh x = log ((1 + x) / (1 - x)) / 2+instance Floating+ (Expression grp lat with db params from (null 'PGnumeric)) where+ pi = UnsafeExpression "pi()"+ exp = unsafeFunction "exp"+ log = unsafeFunction "ln"+ sqrt = unsafeFunction "sqrt"+ b ** x = UnsafeExpression $+ "power(" <> renderSQL b <> ", " <> renderSQL x <> ")"+ logBase b y = log y / log b+ sin = unsafeFunction "sin"+ cos = unsafeFunction "cos"+ tan = unsafeFunction "tan"+ asin = unsafeFunction "asin"+ acos = unsafeFunction "acos"+ atan = unsafeFunction "atan"+ sinh x = (exp x - exp (-x)) / 2+ cosh x = (exp x + exp (-x)) / 2+ tanh x = sinh x / cosh x+ asinh x = log (x + sqrt (x*x + 1))+ acosh x = log (x + sqrt (x*x - 1))+ atanh x = log ((1 + x) / (1 - x)) / 2 -- | Contained by operators-class PGSubset container where- (@>) :: Operator (null0 container) (null1 container) ('Null 'PGbool)+class PGSubset ty where+ (@>) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool) (@>) = unsafeBinaryOp "@>"- (<@) :: Operator (null0 container) (null1 container) ('Null 'PGbool)+ (<@) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool) (<@) = unsafeBinaryOp "<@" instance PGSubset 'PGjsonb instance PGSubset 'PGtsquery instance PGSubset ('PGvararray ty)+instance PGSubset ('PGrange ty) +-- | Intersection operator+class PGIntersect ty where+ (@&&) :: Operator (null0 ty) (null1 ty) ('Null 'PGbool)+ (@&&) = unsafeBinaryOp "&&"+instance PGIntersect ('PGvararray ty)+instance PGIntersect ('PGrange ty)+ instance IsString- (Expression outer commons grp schemas params from (null 'PGtext)) where- fromString str = UnsafeExpression $- "E\'" <> fromString (escape =<< str) <> "\'"+ (Expression grp lat with db params from (null 'PGtext)) where+ fromString+ = UnsafeExpression+ . parenthesized+ . (<> " :: text")+ . escapeQuotedString instance IsString- (Expression outer commons grp schemas params from (null 'PGtsvector)) where- fromString str = UnsafeExpression . parenthesized . (<> " :: tsvector") $- "E\'" <> fromString (escape =<< str) <> "\'"+ (Expression grp lat with db params from (null 'PGtsvector)) where+ fromString+ = UnsafeExpression+ . parenthesized+ . (<> " :: tsvector")+ . escapeQuotedString instance IsString- (Expression outer commons grp schemas params from (null 'PGtsquery)) where- fromString str = UnsafeExpression . parenthesized . (<> " :: tsquery") $- "E\'" <> fromString (escape =<< str) <> "\'"+ (Expression grp lat with db params from (null 'PGtsquery)) where+ fromString+ = UnsafeExpression+ . parenthesized+ . (<> " :: tsquery")+ . escapeQuotedString instance Semigroup- (Expression outer commons grp schemas params from (null ('PGvararray ty))) where+ (Expression grp lat with db params from (null ('PGvararray ty))) where (<>) = unsafeBinaryOp "||" instance Semigroup- (Expression outer commons grp schemas params from (null 'PGjsonb)) where+ (Expression grp lat with db params from (null 'PGjsonb)) where (<>) = unsafeBinaryOp "||" instance Semigroup- (Expression outer commons grp schemas params from (null 'PGtext)) where+ (Expression grp lat with db params from (null 'PGtext)) where (<>) = unsafeBinaryOp "||" instance Semigroup- (Expression outer commons grp schemas params from (null 'PGtsvector)) where+ (Expression grp lat with db params from (null 'PGtsvector)) where (<>) = unsafeBinaryOp "||" instance Monoid- (Expression outer commons grp schemas params from (null 'PGtext)) where+ (Expression grp lat with db params from (null 'PGtext)) where mempty = fromString "" mappend = (<>) instance Monoid- (Expression outer commons grp schemas params from (null 'PGtsvector)) where+ (Expression grp lat with db params from (null 'PGtsvector)) where mempty = fromString "" mappend = (<>)
src/Squeal/PostgreSQL/Expression/Aggregate.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Aggregate-Description: Aggregate functions+Description: aggregate functions and arguments Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Aggregate functions+aggregate functions and arguments -} {-# LANGUAGE@@ -17,99 +17,115 @@ , LambdaCase , MultiParamTypeClasses , OverloadedStrings+ , PatternSynonyms , PolyKinds+ , StandaloneDeriving , TypeFamilies , TypeOperators , UndecidableInstances #-} module Squeal.PostgreSQL.Expression.Aggregate- ( Aggregate (..)- , Distinction (..)+ ( -- * Aggregate+ Aggregate (..)+ , AggregateArg (..)+ , pattern All+ , pattern Alls+ , allNotNull+ , pattern Distinct+ , pattern Distincts+ , distinctNotNull+ , FilterWhere (..)+ -- * Aggregate Types , PGSum , PGAvg ) where -import Control.DeepSeq import Data.ByteString (ByteString)-import Data.Kind import GHC.TypeLits -import qualified GHC.Generics as GHC import qualified Generics.SOP as SOP -import Squeal.PostgreSQL.Alias+import Squeal.PostgreSQL.Type.Alias import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.List+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Expression.Null+import Squeal.PostgreSQL.Expression.Sort+import Squeal.PostgreSQL.Type.List import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL {- | `Aggregate` functions compute a single result from a set of input values.-`Aggregate` functions can be used as `GroupedBy` `Expression`s as well+`Aggregate` functions can be used as `Grouped` `Expression`s as well as `Squeal.PostgreSQL.Expression.Window.WindowFunction`s. -}-class Aggregate expr1 exprN aggr- | aggr -> expr1, aggr -> exprN where+class Aggregate arg expr | expr -> arg where -- | A special aggregation that does not require an input -- -- >>> :{ -- let- -- expression :: Expression '[] commons ('Grouped bys) schemas params from ('NotNull 'PGint8)+ -- expression :: Expression ('Grouped bys) '[] with db params from ('NotNull 'PGint8) -- expression = countStar -- in printSQL expression -- :} -- count(*)- countStar :: aggr ('NotNull 'PGint8)+ countStar :: expr lat with db params from ('NotNull 'PGint8) -- | >>> :{ -- let- -- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)+ -- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8) -- expression = count (All #col) -- in printSQL expression -- :} -- count(ALL "col") count- :: expr1 ty- -- ^ what to count- -> aggr ('NotNull 'PGint8)+ :: arg '[ty] lat with db params from+ -> expr lat with db params from ('NotNull 'PGint8) -- | >>> :{ -- let- -- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)- -- expression = sum_ (Distinct #col)+ -- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)+ -- expression = sum_ (Distinct #col & filterWhere (#col .< 100)) -- in printSQL expression -- :}- -- sum(DISTINCT "col")+ -- sum(DISTINCT "col") FILTER (WHERE ("col" < (100.0 :: numeric))) sum_- :: expr1 (null ty)- -> aggr ('Null (PGSum ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGSum ty)) -- | input values, including nulls, concatenated into an array+ -- >>> :{+ -- let+ -- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null ('PGvararray ('Null 'PGnumeric)))+ -- expression = arrayAgg (All #col & orderBy [AscNullsFirst #col] & filterWhere (#col .< 100))+ -- in printSQL expression+ -- :}+ -- array_agg(ALL "col" ORDER BY "col" ASC NULLS FIRST) FILTER (WHERE ("col" < (100.0 :: numeric))) arrayAgg- :: expr1 ty- -> aggr ('Null ('PGvararray ty))+ :: arg '[ty] lat with db params from+ -> expr lat with db params from ('Null ('PGvararray ty)) -- | aggregates values as a JSON array jsonAgg- :: expr1 ty- -> aggr ('Null 'PGjson)+ :: arg '[ty] lat with db params from+ -> expr lat with db params from ('Null 'PGjson) -- | aggregates values as a JSON array jsonbAgg- :: expr1 ty- -> aggr ('Null 'PGjsonb)+ :: arg '[ty] lat with db params from+ -> expr lat with db params from ('Null 'PGjsonb) {- | the bitwise AND of all non-null input values, or null if none >>> :{ let- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)+ expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4) expression = bitAnd (Distinct #col) in printSQL expression :}@@ -117,16 +133,15 @@ -} bitAnd :: int `In` PGIntegral- => expr1 (null int)- -- ^ what to aggregate- -> aggr ('Null int)+ => arg '[null int] lat with db params from+ -> expr lat with db params from ('Null int) {- | the bitwise OR of all non-null input values, or null if none >>> :{ let- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)+ expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4) expression = bitOr (All #col) in printSQL expression :}@@ -134,307 +149,376 @@ -} bitOr :: int `In` PGIntegral- => expr1 (null int)- -- ^ what to aggregate- -> aggr ('Null int)+ => arg '[null int] lat with db params from+ -> expr lat with db params from ('Null int) {- | true if all input values are true, otherwise false >>> :{ let- winFun :: WindowFunction '[] commons 'Ungrouped schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)- winFun = boolAnd #col+ winFun :: WindowFunction 'Ungrouped '[] with db params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)+ winFun = boolAnd (Window #col) in printSQL winFun :} bool_and("col") -} boolAnd- :: expr1 (null 'PGbool)- -- ^ what to aggregate- -> aggr ('Null 'PGbool)+ :: arg '[null 'PGbool] lat with db params from+ -> expr lat with db params from ('Null 'PGbool) {- | true if at least one input value is true, otherwise false >>> :{ let- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)+ expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool) expression = boolOr (All #col) in printSQL expression :} bool_or(ALL "col") -} boolOr- :: expr1 (null 'PGbool)- -- ^ what to aggregate- -> aggr ('Null 'PGbool)+ :: arg '[null 'PGbool] lat with db params from+ -> expr lat with db params from ('Null 'PGbool) {- | equivalent to `boolAnd` >>> :{ let- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)+ expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool) expression = every (Distinct #col) in printSQL expression :} every(DISTINCT "col") -} every- :: expr1 (null 'PGbool)- -- ^ what to aggregate- -> aggr ('Null 'PGbool)+ :: arg '[null 'PGbool] lat with db params from+ -> expr lat with db params from ('Null 'PGbool) {- |maximum value of expression across all input values-} max_- :: expr1 (null ty)- -- ^ what to maximize- -> aggr ('Null ty)+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null ty) -- | minimum value of expression across all input values min_- :: expr1 (null ty)- -- ^ what to minimize- -> aggr ('Null ty)+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null ty) -- | the average (arithmetic mean) of all input values avg- :: expr1 (null ty)- -- ^ what to average- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) {- | correlation coefficient >>> :{ let- expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)- expression = corr (All (#y *: #x))+ expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)+ expression = corr (Alls (#y *: #x)) in printSQL expression :} corr(ALL "y", "x") -} corr- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) {- | population covariance >>> :{ let- expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)- expression = covarPop (All (#y *: #x))+ expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)+ expression = covarPop (Alls (#y *: #x)) in printSQL expression :} covar_pop(ALL "y", "x") -} covarPop- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) {- | sample covariance >>> :{ let- winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)- winFun = covarSamp (#y *: #x)+ winFun :: WindowFunction 'Ungrouped '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)+ winFun = covarSamp (Windows (#y *: #x)) in printSQL winFun :} covar_samp("y", "x") -} covarSamp- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) {- | average of the independent variable (sum(X)/N) >>> :{ let- expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)- expression = regrAvgX (All (#y *: #x))+ expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)+ expression = regrAvgX (Alls (#y *: #x)) in printSQL expression :} regr_avgx(ALL "y", "x") -} regrAvgX- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) {- | average of the dependent variable (sum(Y)/N) >>> :{ let- winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)- winFun = regrAvgY (#y *: #x)+ winFun :: WindowFunction 'Ungrouped '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)+ winFun = regrAvgY (Windows (#y *: #x)) in printSQL winFun :} regr_avgy("y", "x") -} regrAvgY- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) {- | number of input rows in which both expressions are nonnull >>> :{ let- winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)- winFun = regrCount (#y *: #x)+ winFun :: WindowFunction 'Ungrouped '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)+ winFun = regrCount (Windows (#y *: #x)) in printSQL winFun :} regr_count("y", "x") -} regrCount- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGint8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGint8) {- | y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs >>> :{ let- expression :: Expression '[] c ('Grouped g) s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)- expression = regrIntercept (All (#y *: #x))+ expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)+ expression = regrIntercept (Alls (#y *: #x)) in printSQL expression :} regr_intercept(ALL "y", "x") -} regrIntercept- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) -- | @regr_r2(Y, X)@, square of the correlation coefficient regrR2- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) -- | @regr_slope(Y, X)@, slope of the least-squares-fit linear equation -- determined by the (X, Y) pairs regrSlope- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) -- | @regr_sxx(Y, X)@, sum(X^2) - sum(X)^2/N -- (“sum of squares” of the independent variable) regrSxx- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) -- | @regr_sxy(Y, X)@, sum(X*Y) - sum(X) * sum(Y)/N -- (“sum of products” of independent times dependent variable) regrSxy- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) -- | @regr_syy(Y, X)@, sum(Y^2) - sum(Y)^2/N -- (“sum of squares” of the dependent variable) regrSyy- :: exprN '[null 'PGfloat8, null 'PGfloat8]- -> aggr ('Null 'PGfloat8)+ :: arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from+ -> expr lat with db params from ('Null 'PGfloat8) -- | historical alias for `stddevSamp` stddev- :: expr1 (null ty)- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) -- | population standard deviation of the input values stddevPop- :: expr1 (null ty)- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) -- | sample standard deviation of the input values stddevSamp- :: expr1 (null ty)- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) -- | historical alias for `varSamp` variance- :: expr1 (null ty)- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) -- | population variance of the input values -- (square of the population standard deviation) varPop- :: expr1 (null ty)- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) -- | sample variance of the input values -- (square of the sample standard deviation) varSamp- :: expr1 (null ty)- -> aggr ('Null (PGAvg ty))+ :: arg '[null ty] lat with db params from+ -> expr lat with db params from ('Null (PGAvg ty)) {- |-`Distinction`s are used for the input of `Aggregate` `Expression`s.-`All` invokes the aggregate once for each input row.-`Distinct` invokes the aggregate once for each distinct value of the expression-(or distinct set of values, for multiple expressions) found in the input+`AggregateArg`s are used for the input of `Aggregate` `Expression`s. -}-data Distinction (expr :: kind -> Type) (ty :: kind)- = All (expr ty)- | Distinct (expr ty)- deriving (GHC.Generic,Show,Eq,Ord)-instance NFData (Distinction (Expression outer commons grp schemas params from) ty)-instance RenderSQL (Distinction (Expression outer commons grp schemas params from) ty) where+data AggregateArg+ (xs :: [NullType])+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType])+ (from :: FromType)+ = AggregateAll+ { aggregateArgs :: NP (Expression 'Ungrouped lat with db params from) xs+ , aggregateOrder :: [SortExpression 'Ungrouped lat with db params from]+ , aggregateFilter :: [Condition 'Ungrouped lat with db params from] }+ | AggregateDistinct+ { aggregateArgs :: NP (Expression 'Ungrouped lat with db params from) xs+ , aggregateOrder :: [SortExpression 'Ungrouped lat with db params from]+ , aggregateFilter :: [Condition 'Ungrouped lat with db params from] }++instance SOP.SListI xs => RenderSQL (AggregateArg xs lat with db params from) where renderSQL = \case- All x -> "ALL" <+> renderSQL x- Distinct x -> "DISTINCT" <+> renderSQL x-instance SOP.SListI tys => RenderSQL- (Distinction (NP (Expression outer commons grp schemas params from)) tys) where- renderSQL = \case- All xs -> "ALL" <+> renderCommaSeparated renderSQL xs- Distinct xs -> "DISTINCT" <+> renderCommaSeparated renderSQL xs+ AggregateAll args sorts filters ->+ parenthesized+ ("ALL" <+> renderCommaSeparated renderSQL args<> renderSQL sorts)+ <> renderFilters filters+ AggregateDistinct args sorts filters ->+ parenthesized+ ("DISTINCT" <+> renderCommaSeparated renderSQL args <> renderSQL sorts)+ <> renderFilters filters+ where+ renderFilter wh = "FILTER" <+> parenthesized ("WHERE" <+> wh)+ renderFilters = \case+ [] -> ""+ wh:whs -> " " <> renderFilter (renderSQL (foldr (.&&) wh whs)) -instance Aggregate- (Distinction (Expression outer commons 'Ungrouped schemas params from))- (Distinction (NP (Expression outer commons 'Ungrouped schemas params from)))- (Expression outer commons ('Grouped bys) schemas params from) where- countStar = UnsafeExpression "count(*)"- count = unsafeAggregate1 "count"- sum_ = unsafeAggregate1 "sum"- arrayAgg = unsafeAggregate1 "array_agg"- jsonAgg = unsafeAggregate1 "json_agg"- jsonbAgg = unsafeAggregate1 "jsonb_agg"- bitAnd = unsafeAggregate1 "bit_and"- bitOr = unsafeAggregate1 "bit_or"- boolAnd = unsafeAggregate1 "bool_and"- boolOr = unsafeAggregate1 "bool_or"- every = unsafeAggregate1 "every"- max_ = unsafeAggregate1 "max"- min_ = unsafeAggregate1 "min"- avg = unsafeAggregate1 "avg"- corr = unsafeAggregateN "corr"- covarPop = unsafeAggregateN "covar_pop"- covarSamp = unsafeAggregateN "covar_samp"- regrAvgX = unsafeAggregateN "regr_avgx"- regrAvgY = unsafeAggregateN "regr_avgy"- regrCount = unsafeAggregateN "regr_count"- regrIntercept = unsafeAggregateN "regr_intercept"- regrR2 = unsafeAggregateN "regr_r2"- regrSlope = unsafeAggregateN "regr_slope"- regrSxx = unsafeAggregateN "regr_sxx"- regrSxy = unsafeAggregateN "regr_sxy"- regrSyy = unsafeAggregateN "regr_syy"- stddev = unsafeAggregate1 "stddev"- stddevPop = unsafeAggregate1 "stddev_pop"- stddevSamp = unsafeAggregate1 "stddev_samp"- variance = unsafeAggregate1 "variance"- varPop = unsafeAggregate1 "var_pop"- varSamp = unsafeAggregate1 "var_samp"+instance OrderBy (AggregateArg xs) 'Ungrouped where+ orderBy sorts1 = \case+ AggregateAll xs sorts0 whs -> AggregateAll xs (sorts0 ++ sorts1) whs+ AggregateDistinct xs sorts0 whs -> AggregateDistinct xs (sorts0 ++ sorts1) whs --- | escape hatch to define aggregate functions-unsafeAggregate1- :: ByteString -- ^ aggregate function- -> Distinction (Expression outer commons 'Ungrouped schemas params from) x- -> Expression outer commons ('Grouped bys) schemas params from y-unsafeAggregate1 fun x = UnsafeExpression $ fun <> parenthesized (renderSQL x)+-- | `All` invokes the aggregate on a single+-- argument once for each input row.+pattern All+ :: Expression 'Ungrouped lat with db params from x+ -> AggregateArg '[x] lat with db params from+pattern All x = Alls (x :* Nil) -unsafeAggregateN+-- | `All` invokes the aggregate on multiple+-- arguments once for each input row.+pattern Alls+ :: NP (Expression 'Ungrouped lat with db params from) xs+ -> AggregateArg xs lat with db params from+pattern Alls xs = AggregateAll xs [] []++-- | `allNotNull` invokes the aggregate on a single+-- argument once for each input row where the argument+-- is not null+allNotNull+ :: Expression 'Ungrouped lat with db params from ('Null x)+ -> AggregateArg '[ 'NotNull x] lat with db params from+allNotNull x = All (unsafeNotNull x) & filterWhere (not_ (isNull x))++{- |+`Distinct` invokes the aggregate once for each+distinct value of the expression found in the input.+-}+pattern Distinct+ :: Expression 'Ungrouped lat with db params from x+ -> AggregateArg '[x] lat with db params from+pattern Distinct x = Distincts (x :* Nil)++{- |+`Distincts` invokes the aggregate once for each+distinct set of values, for multiple expressions, found in the input.+-}+pattern Distincts+ :: NP (Expression 'Ungrouped lat with db params from) xs+ -> AggregateArg xs lat with db params from+pattern Distincts xs = AggregateDistinct xs [] []++{- |+`distinctNotNull` invokes the aggregate once for each+distinct, not null value of the expression found in the input.+-}+distinctNotNull+ :: Expression 'Ungrouped lat with db params from ('Null x)+ -> AggregateArg '[ 'NotNull x] lat with db params from+distinctNotNull x = Distinct (unsafeNotNull x) & filterWhere (not_ (isNull x))++-- | Permits filtering+-- `Squeal.PostgreSQL.Expression.Window.WindowArg`s and `AggregateArg`s+class FilterWhere arg grp | arg -> grp where+ {- |+ If `filterWhere` is specified, then only the input rows for which+ the `Condition` evaluates to true are fed to the aggregate function;+ other rows are discarded.+ -}+ filterWhere+ :: Condition grp lat with db params from+ -> arg xs lat with db params from+ -> arg xs lat with db params from+instance FilterWhere AggregateArg 'Ungrouped where+ filterWhere wh = \case+ AggregateAll xs sorts whs -> AggregateAll xs sorts (wh : whs)+ AggregateDistinct xs sorts whs -> AggregateDistinct xs sorts (wh : whs)++instance Aggregate AggregateArg (Expression ('Grouped bys)) where+ countStar = UnsafeExpression "count(*)"+ count = unsafeAggregate "count"+ sum_ = unsafeAggregate "sum"+ arrayAgg = unsafeAggregate "array_agg"+ jsonAgg = unsafeAggregate "json_agg"+ jsonbAgg = unsafeAggregate "jsonb_agg"+ bitAnd = unsafeAggregate "bit_and"+ bitOr = unsafeAggregate "bit_or"+ boolAnd = unsafeAggregate "bool_and"+ boolOr = unsafeAggregate "bool_or"+ every = unsafeAggregate "every"+ max_ = unsafeAggregate "max"+ min_ = unsafeAggregate "min"+ avg = unsafeAggregate "avg"+ corr = unsafeAggregate "corr"+ covarPop = unsafeAggregate "covar_pop"+ covarSamp = unsafeAggregate "covar_samp"+ regrAvgX = unsafeAggregate "regr_avgx"+ regrAvgY = unsafeAggregate "regr_avgy"+ regrCount = unsafeAggregate "regr_count"+ regrIntercept = unsafeAggregate "regr_intercept"+ regrR2 = unsafeAggregate "regr_r2"+ regrSlope = unsafeAggregate "regr_slope"+ regrSxx = unsafeAggregate "regr_sxx"+ regrSxy = unsafeAggregate "regr_sxy"+ regrSyy = unsafeAggregate "regr_syy"+ stddev = unsafeAggregate "stddev"+ stddevPop = unsafeAggregate "stddev_pop"+ stddevSamp = unsafeAggregate "stddev_samp"+ variance = unsafeAggregate "variance"+ varPop = unsafeAggregate "var_pop"+ varSamp = unsafeAggregate "var_samp"++-- | escape hatch to define aggregate functions+unsafeAggregate :: SOP.SListI xs => ByteString -- ^ function- -> Distinction (NP (Expression outer commons 'Ungrouped schemas params from)) xs- -> Expression outer commons ('Grouped bys) schemas params from y-unsafeAggregateN fun xs = UnsafeExpression $ fun <> parenthesized (renderSQL xs)+ -> AggregateArg xs lat with db params from+ -> Expression ('Grouped bys) lat with db params from y+unsafeAggregate fun xs = UnsafeExpression $ fun <> renderSQL xs --- | A type family that calculates `PGSum``PGType` of+-- | A type family that calculates `PGSum` `PGType` of -- a given argument `PGType`. type family PGSum ty where PGSum 'PGint2 = 'PGint8
+ src/Squeal/PostgreSQL/Expression/Array.hs view
@@ -0,0 +1,139 @@+{-|+Module: Squeal.PostgreSQL.Expression.Array+Description: array functions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++array functions+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , DataKinds+ , FlexibleContexts+ , FlexibleInstances+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Expression.Array+ ( -- * Array Functions+ array+ , array0+ , array1+ , array2+ , cardinality+ , index+ , unnest+ ) where++import Data.String+import Data.Word (Word64)++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Type+import Squeal.PostgreSQL.Query.From.Set+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++-- | Construct an array.+-- >>> printSQL $ array [null_, false, true]+-- ARRAY[NULL, FALSE, TRUE]+array+ :: [Expression grp lat with db params from ty]+ -- ^ array elements+ -> Expression grp lat with db params from (null ('PGvararray ty))+array xs = UnsafeExpression $ "ARRAY" <>+ bracketed (commaSeparated (renderSQL <$> xs))++-- | Safely construct an empty array.+-- >>> printSQL $ array0 text+-- (ARRAY[] :: text[])+array0+ :: TypeExpression db ty+ -> Expression grp lat with db params from (null ('PGvararray ty))+array0 ty = array [] & astype (vararray ty)++{- | Construct a fixed length array.++>>> printSQL $ array1 (null_ :* false *: true)+ARRAY[NULL, FALSE, TRUE]++>>> :type array1 (null_ :* false *: true)+array1 (null_ :* false *: true)+ :: Expression+ grp+ lat+ with+ db+ params+ from+ (null ('PGfixarray '[3] ('Null 'PGbool)))+-}+array1+ :: (n ~ Length tys, SOP.All ((~) ty) tys)+ => NP (Expression grp lat with db params from) tys+ -- ^ array elements+ -> Expression grp lat with db params from (null ('PGfixarray '[n] ty))+array1 xs = UnsafeExpression $ "ARRAY" <>+ bracketed (renderCommaSeparated renderSQL xs)++{- | Construct a fixed size matrix.++>>> printSQL $ array2 ((null_ :* false *: true) *: (false :* null_ *: true))+ARRAY[[NULL, FALSE, TRUE], [FALSE, NULL, TRUE]]++>>> :type array2 ((null_ :* false *: true) *: (false :* null_ *: true))+array2 ((null_ :* false *: true) *: (false :* null_ *: true))+ :: Expression+ grp+ lat+ with+ db+ params+ from+ (null ('PGfixarray '[2, 3] ('Null 'PGbool)))+-}+array2+ :: ( SOP.All ((~) tys) tyss+ , SOP.All SOP.SListI tyss+ , Length tyss ~ n1+ , SOP.All ((~) ty) tys+ , Length tys ~ n2 )+ => NP (NP (Expression grp lat with db params from)) tyss+ -- ^ matrix elements+ -> Expression grp lat with db params from (null ('PGfixarray '[n1,n2] ty))+array2 xss = UnsafeExpression $ "ARRAY" <>+ bracketed (renderCommaSeparatedConstraint @SOP.SListI (bracketed . renderCommaSeparated renderSQL) xss)++-- | >>> printSQL $ cardinality (array [null_, false, true])+-- cardinality(ARRAY[NULL, FALSE, TRUE])+cardinality :: null ('PGvararray ty) --> null 'PGint8+cardinality = unsafeFunction "cardinality"++-- | >>> printSQL $ array [null_, false, true] & index 2+-- (ARRAY[NULL, FALSE, TRUE])[2]+index+ :: Word64 -- ^ index+ -> null ('PGvararray ty) --> NullifyType ty+index n expr = UnsafeExpression $+ parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"++-- | Expand an array to a set of rows+unnest :: null ('PGvararray ty) -|-> ("unnest" ::: '["unnest" ::: ty])+unnest = unsafeSetFunction "unnest"
− src/Squeal/PostgreSQL/Expression/Collection.hs
@@ -1,169 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Expression.Collection-Description: Array and composite functions-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--Array and composite functions--}--{-# LANGUAGE- AllowAmbiguousTypes- , DataKinds- , FlexibleContexts- , FlexibleInstances- , MultiParamTypeClasses- , OverloadedLabels- , OverloadedStrings- , RankNTypes- , ScopedTypeVariables- , TypeApplications- , TypeFamilies- , TypeOperators- , UndecidableInstances-#-}--module Squeal.PostgreSQL.Expression.Collection- ( array- , array1- , array2- , cardinality- , index- , unnest- , row- , field- ) where--import Data.String-import Data.Word (Word64)--import qualified Generics.SOP as SOP--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Expression.SetOf-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema---- $setup--- >>> import Squeal.PostgreSQL---- | >>> printSQL $ array [null_, false, true]--- ARRAY[NULL, FALSE, TRUE]-array- :: [Expression outer commons grp schemas params from ty]- -- ^ array elements- -> Expression outer commons grp schemas params from (null ('PGvararray ty))-array xs = UnsafeExpression $ "ARRAY" <>- bracketed (commaSeparated (renderSQL <$> xs))--{- | construct a 1-dimensional fixed length array-->>> printSQL $ array1 (null_ :* false *: true)-ARRAY[NULL, FALSE, TRUE]-->>> :type array1 (null_ :* false *: true)-array1 (null_ :* false *: true)- :: Expression- outer- commons- grp- schemas- params- from- (null ('PGfixarray '[3] ('Null 'PGbool)))--}-array1- :: (n ~ Length tys, SOP.All ((~) ty) tys)- => NP (Expression outer commons grp schemas params from) tys- -> Expression outer commons grp schemas params from (null ('PGfixarray '[n] ty))-array1 xs = UnsafeExpression $ "ARRAY" <>- bracketed (renderCommaSeparated renderSQL xs)--{- | construct a 2-dimensional fixed length array-->>> printSQL $ array2 ((null_ :* false *: true) *: (false :* null_ *: true))-ARRAY[[NULL, FALSE, TRUE], [FALSE, NULL, TRUE]]-->>> :type array2 ((null_ :* false *: true) *: (false :* null_ *: true))-array2 ((null_ :* false *: true) *: (false :* null_ *: true))- :: Expression- outer- commons- grp- schemas- params- from- (null ('PGfixarray '[2, 3] ('Null 'PGbool)))--}-array2- :: ( SOP.All ((~) tys) tyss- , SOP.All SOP.SListI tyss- , Length tyss ~ n1- , SOP.All ((~) ty) tys- , Length tys ~ n2 )- => NP (NP (Expression outer commons grp schemas params from)) tyss- -> Expression outer commons grp schemas params from (null ('PGfixarray '[n1,n2] ty))-array2 xss = UnsafeExpression $ "ARRAY" <>- bracketed (renderCommaSeparatedConstraint @SOP.SListI (bracketed . renderCommaSeparated renderSQL) xss)---- | >>> printSQL $ cardinality (array [null_, false, true])--- cardinality(ARRAY[NULL, FALSE, TRUE])-cardinality :: null ('PGvararray ty) :--> null 'PGint8-cardinality = unsafeFunction "cardinality"---- | >>> printSQL $ array [null_, false, true] & index 2--- (ARRAY[NULL, FALSE, TRUE])[2]-index- :: Word64 -- ^ index- -> null ('PGvararray ty) :--> NullifyType ty-index n expr = UnsafeExpression $- parenthesized (renderSQL expr) <> "[" <> fromString (show n) <> "]"---- | Expand an array to a set of rows-unnest :: SetOfFunction "unnest" (null ('PGvararray ty)) '["unnest" ::: ty]-unnest = unsafeSetOfFunction---- | A row constructor is an expression that builds a row value--- (also called a composite value) using values for its member fields.------ >>> :{--- type Complex = 'PGcomposite--- '[ "real" ::: 'NotNull 'PGfloat8--- , "imaginary" ::: 'NotNull 'PGfloat8 ]--- :}------ >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer commons grp schemas params from ('NotNull Complex)--- >>> printSQL i--- ROW(0, 1)-row- :: SOP.SListI row- => NP (Aliased (Expression outer commons grp schemas params from)) row- -- ^ zero or more expressions for the row field values- -> Expression outer commons grp schemas params from (null ('PGcomposite row))-row exprs = UnsafeExpression $ "ROW" <> parenthesized- (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)---- | >>> :{--- type Complex = 'PGcomposite--- '[ "real" ::: 'NotNull 'PGfloat8--- , "imaginary" ::: 'NotNull 'PGfloat8 ]--- type Schema = '["complex" ::: 'Typedef Complex]--- :}------ >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression outer '[] grp (Public Schema) from params ('NotNull Complex)--- >>> printSQL $ i & field #complex #imaginary--- (ROW(0, 1)::"complex")."imaginary"-field- :: ( Has sch schemas schema- , Has tydef schema ('Typedef ('PGcomposite row))- , Has field row ty)- => QualifiedAlias sch tydef -- ^ row type- -> Alias field -- ^ field name- -> Expression outer commons grp schemas params from ('NotNull ('PGcomposite row))- -> Expression outer commons grp schemas params from ty-field td fld expr = UnsafeExpression $- parenthesized (renderSQL expr <> "::" <> renderSQL td)- <> "." <> renderSQL fld
src/Squeal/PostgreSQL/Expression/Comparison.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Comparison-Description: Comparison expressions+Description: comparison functions and operators Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Comparison functions and operators+comparison functions and operators -} {-# LANGUAGE@@ -16,19 +16,23 @@ #-} module Squeal.PostgreSQL.Expression.Comparison- ( (.==)+ ( -- * Comparison Operators+ (.==) , (./=) , (.>=) , (.<) , (.<=) , (.>)+ -- * Comparison Functions , greatest , least+ -- * Between , BetweenExpr , between , notBetween , betweenSymmetric , notBetweenSymmetric+ -- * Null Comparison , isDistinctFrom , isNotDistinctFrom , isTrue@@ -44,7 +48,7 @@ import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Expression.Logic import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -88,7 +92,7 @@ (.>) = unsafeBinaryOp ">" infix 4 .> --- | >>> let expr = greatest [param @1] currentTimestamp :: Expression outer commons grp schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)+-- | >>> let expr = greatest [param @1] currentTimestamp :: Expression grp lat with db '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz) -- >>> printSQL expr -- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP) greatest :: FunctionVar ty ty ty@@ -103,11 +107,11 @@ A @RankNType@ for comparison expressions like `between`. -} type BetweenExpr- = forall outer commons grp schemas params from ty- . Expression outer commons grp schemas params from ty- -> ( Expression outer commons grp schemas params from ty- , Expression outer commons grp schemas params from ty ) -- ^ bounds- -> Condition outer commons grp schemas params from+ = forall grp lat with db params from ty+ . Expression grp lat with db params from ty+ -> ( Expression grp lat with db params from ty+ , Expression grp lat with db params from ty ) -- ^ bounds+ -> Condition grp lat with db params from unsafeBetweenExpr :: ByteString -> BetweenExpr unsafeBetweenExpr fun a (x,y) = UnsafeExpression $@@ -162,45 +166,45 @@ >>> printSQL $ true & isTrue (TRUE IS TRUE) -}-isTrue :: null0 'PGbool :--> null1 'PGbool-isTrue = unsafeUnaryOpR "IS TRUE"+isTrue :: null0 'PGbool --> null1 'PGbool+isTrue = unsafeRightOp "IS TRUE" {- | is false or unknown >>> printSQL $ true & isNotTrue (TRUE IS NOT TRUE) -}-isNotTrue :: null0 'PGbool :--> null1 'PGbool-isNotTrue = unsafeUnaryOpR "IS NOT TRUE"+isNotTrue :: null0 'PGbool --> null1 'PGbool+isNotTrue = unsafeRightOp "IS NOT TRUE" {- | is false >>> printSQL $ true & isFalse (TRUE IS FALSE) -}-isFalse :: null0 'PGbool :--> null1 'PGbool-isFalse = unsafeUnaryOpR "IS FALSE"+isFalse :: null0 'PGbool --> null1 'PGbool+isFalse = unsafeRightOp "IS FALSE" {- | is true or unknown >>> printSQL $ true & isNotFalse (TRUE IS NOT FALSE) -}-isNotFalse :: null0 'PGbool :--> null1 'PGbool-isNotFalse = unsafeUnaryOpR "IS NOT FALSE"+isNotFalse :: null0 'PGbool --> null1 'PGbool+isNotFalse = unsafeRightOp "IS NOT FALSE" {- | is unknown >>> printSQL $ true & isUnknown (TRUE IS UNKNOWN) -}-isUnknown :: null0 'PGbool :--> null1 'PGbool-isUnknown = unsafeUnaryOpR "IS UNKNOWN"+isUnknown :: null0 'PGbool --> null1 'PGbool+isUnknown = unsafeRightOp "IS UNKNOWN" {- | is true or false >>> printSQL $ true & isNotUnknown (TRUE IS NOT UNKNOWN) -}-isNotUnknown :: null0 'PGbool :--> null1 'PGbool-isNotUnknown = unsafeUnaryOpR "IS NOT UNKNOWN"+isNotUnknown :: null0 'PGbool --> null1 'PGbool+isNotUnknown = unsafeRightOp "IS NOT UNKNOWN"
+ src/Squeal/PostgreSQL/Expression/Composite.hs view
@@ -0,0 +1,93 @@+{-|+Module: Squeal.PostgreSQL.Expression.Composite+Description: composite functions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++composite functions+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , DataKinds+ , FlexibleContexts+ , FlexibleInstances+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Expression.Composite+ ( -- * Composite Functions+ row+ , rowStar+ , field+ ) where++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++-- | A row constructor is an expression that builds a row value+-- (also called a composite value) using values for its member fields.+--+-- >>> :{+-- type Complex = 'PGcomposite+-- '[ "real" ::: 'NotNull 'PGfloat8+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]+-- :}+--+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression grp lat with db params from ('NotNull Complex)+-- >>> printSQL i+-- ROW((0.0 :: float8), (1.0 :: float8))+row+ :: SOP.SListI row+ => NP (Aliased (Expression grp lat with db params from)) row+ -- ^ zero or more expressions for the row field values+ -> Expression grp lat with db params from (null ('PGcomposite row))+row exprs = UnsafeExpression $ "ROW" <> parenthesized+ (renderCommaSeparated (\ (expr `As` _) -> renderSQL expr) exprs)++-- | A row constructor on all columns in a table expression.+rowStar+ :: Has tab from row+ => Alias tab+ -> Expression grp lat with db params from (null ('PGcomposite row))+rowStar tab = UnsafeExpression $ "ROW" <>+ parenthesized (renderSQL tab <> ".*")++-- | >>> :{+-- type Complex = 'PGcomposite+-- '[ "real" ::: 'NotNull 'PGfloat8+-- , "imaginary" ::: 'NotNull 'PGfloat8 ]+-- type Schema = '["complex" ::: 'Typedef Complex]+-- :}+--+-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression lat '[] grp (Public Schema) from params ('NotNull Complex)+-- >>> printSQL $ i & field #complex #imaginary+-- (ROW((0.0 :: float8), (1.0 :: float8))::"complex")."imaginary"+field+ :: ( Has sch db schema+ , Has tydef schema ('Typedef ('PGcomposite row))+ , Has field row ty)+ => QualifiedAlias sch tydef -- ^ row type+ -> Alias field -- ^ field name+ -> Expression grp lat with db params from ('NotNull ('PGcomposite row))+ -> Expression grp lat with db params from ty+field td fld expr = UnsafeExpression $+ parenthesized (renderSQL expr <> "::" <> renderSQL td)+ <> "." <> renderSQL fld
+ src/Squeal/PostgreSQL/Expression/Default.hs view
@@ -0,0 +1,60 @@+{-|+Module: Squeal.PostgreSQL.Expression.Default+Description: optional expressions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++optional expressions+-}++{-# LANGUAGE+ DataKinds+ , GADTs+ , LambdaCase+ , OverloadedStrings+ , PatternSynonyms+ , PolyKinds+ , QuantifiedConstraints+ , RankNTypes+ , TypeOperators+#-}++module Squeal.PostgreSQL.Expression.Default+ ( -- * Default+ Optional (..)+ , mapOptional+ , pattern NotDefault+ ) where++import Data.Kind+import Generics.SOP++import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- | `Optional` is either `Default` or `Set`ting of a value,+-- parameterized by an appropriate `Optionality`.+data Optional (expr :: k -> Type) (ty :: (Optionality, k)) where+ -- | Use the `Default` value for a column.+ Default :: Optional expr ('Def :=> ty)+ -- | `Set` a value for a column.+ Set :: expr ty -> Optional expr (def :=> ty)++instance (forall x. RenderSQL (expr x)) => RenderSQL (Optional expr ty) where+ renderSQL = \case+ Default -> "DEFAULT"+ Set x -> renderSQL x++-- | Map a function over an `Optional` expression.+mapOptional+ :: (expr x -> expr y)+ -> Optional expr (def :=> x)+ -> Optional expr (def :=> y)+mapOptional f = \case+ Default -> Default+ Set x -> Set (f x)++-- | `NotDefault` pattern analagous to `Just`.+pattern NotDefault :: ty -> Optional I ('Def :=> ty)+pattern NotDefault x = Set (I x)
+ src/Squeal/PostgreSQL/Expression/Inline.hs view
@@ -0,0 +1,331 @@+{-|+Module: Squeal.PostgreSQL.Expression.Inline+Description: inline expressions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++inline expressions+-}++{-# LANGUAGE+ DataKinds+ , FlexibleContexts+ , FlexibleInstances+ , LambdaCase+ , MultiParamTypeClasses+ , MultiWayIf+ , OverloadedStrings+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , TypeSynonymInstances+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Expression.Inline+ ( -- * Inline+ Inline (..)+ , InlineParam (..)+ , InlineField (..)+ , inlineFields+ , InlineColumn (..)+ , inlineColumns+ ) where++import Data.Binary.Builder (toLazyByteString)+import Data.ByteString.Lazy (toStrict)+import Data.ByteString.Builder (doubleDec, floatDec, int16Dec, int32Dec, int64Dec)+import Data.ByteString.Builder.Scientific (scientificBuilder)+import Data.Int (Int16, Int32, Int64)+import Data.Kind (Type)+import Data.Scientific (Scientific)+import Data.String+import Data.Text (Text)+import Data.Time.Clock (DiffTime, diffTimeToPicoseconds, UTCTime)+import Data.Time.Format (formatTime, defaultTimeLocale)+import Data.Time.Calendar (Day, toGregorian)+import Data.Time.LocalTime (LocalTime(LocalTime), TimeOfDay(TimeOfDay), TimeZone)+import Data.UUID.Types (UUID, toASCIIBytes)+import Data.Vector (Vector, toList)+import Database.PostgreSQL.LibPQ (Oid(Oid))+import GHC.TypeLits++import qualified Data.Aeson as JSON+import qualified Data.Text as Text+import qualified Data.Text.Lazy as Lazy (Text)+import qualified Data.Text.Lazy as Lazy.Text+import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP++import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Array+import Squeal.PostgreSQL.Expression.Default+import Squeal.PostgreSQL.Expression.Composite+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Expression.Null+import Squeal.PostgreSQL.Expression.Range+import Squeal.PostgreSQL.Expression.Time+import Squeal.PostgreSQL.Expression.Type+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.PG+import Squeal.PostgreSQL.Type.Schema++{- |+The `Inline` class allows embedding a Haskell value directly+as an `Expression` using `inline`.++>>> printSQL (inline 'a')+(E'a' :: char(1))++>>> printSQL (inline (1 :: Double))+(1.0 :: float8)++>>> printSQL (inline (Json ([1, 2] :: [Double])))+('[1.0,2.0]' :: json)++>>> printSQL (inline (Enumerated GT))+'GT'+-}+class Inline x where inline :: x -> Expr (null (PG x))+instance Inline Bool where+ inline = \case+ True -> true+ False -> false+instance JSON.ToJSON x => Inline (Json x) where+ inline = inferredtype . UnsafeExpression+ . singleQuotedUtf8 . toStrict . JSON.encode . getJson+instance JSON.ToJSON x => Inline (Jsonb x) where+ inline = inferredtype . UnsafeExpression+ . singleQuotedUtf8 . toStrict . JSON.encode . getJsonb+instance Inline Char where+ inline chr = inferredtype . UnsafeExpression $+ "E\'" <> fromString (escape chr) <> "\'"+instance Inline String where inline = fromString+instance Inline Int16 where+ inline+ = inferredtype+ . UnsafeExpression+ . toStrict+ . toLazyByteString+ . int16Dec+instance Inline Int32 where+ inline+ = inferredtype+ . UnsafeExpression+ . toStrict+ . toLazyByteString+ . int32Dec+instance Inline Int64 where+ inline x =+ if x == minBound+ -- For some reason Postgres throws an error with+ -- (-9223372036854775808 :: int8)+ -- even though it's a valid lowest value for int8+ then inline (x+1) - 1+ else inferredtype+ . UnsafeExpression+ . toStrict+ . toLazyByteString+ $ int64Dec x+instance Inline Float where+ inline x = inferredtype . UnsafeExpression $+ if isNaN x || isInfinite x+ then singleQuotedUtf8 (decimal x)+ else decimal x+ where+ decimal = toStrict . toLazyByteString . floatDec+instance Inline Double where+ inline x = inferredtype . UnsafeExpression $+ if isNaN x || isInfinite x+ then singleQuotedUtf8 (decimal x)+ else decimal x+ where+ decimal = toStrict . toLazyByteString . doubleDec+instance Inline Scientific where+ inline+ = inferredtype+ . UnsafeExpression+ . toStrict+ . toLazyByteString+ . scientificBuilder+instance Inline Text where inline = fromString . Text.unpack+instance Inline Lazy.Text where inline = fromString . Lazy.Text.unpack+instance (KnownNat n, 1 <= n) => Inline (VarChar n) where+ inline+ = inferredtype+ . UnsafeExpression+ . escapeQuotedText+ . getVarChar+instance (KnownNat n, 1 <= n) => Inline (FixChar n) where+ inline+ = inferredtype+ . UnsafeExpression+ . escapeQuotedText+ . getFixChar+instance Inline DiffTime where+ inline dt =+ let+ picosecs = diffTimeToPicoseconds dt+ (secs,leftover) = picosecs `quotRem` 1000000000000+ microsecs = leftover `quot` 1000000+ in+ inferredtype $+ interval_ (fromIntegral secs) Seconds+ +! interval_ (fromIntegral microsecs) Microseconds+instance Inline Day where+ inline day =+ let (y,m,d) = toGregorian day+ in inferredtype $ makeDate (fromInteger y :* fromIntegral m *: fromIntegral d)+instance Inline UTCTime where+ inline+ = inferredtype+ . UnsafeExpression+ . singleQuotedUtf8+ . fromString+ . formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S%Q%z"+instance Inline (TimeOfDay, TimeZone) where+ inline (hms, tz)+ = inferredtype+ . UnsafeExpression+ . singleQuotedUtf8+ . fromString+ $ formatTime defaultTimeLocale "%H:%M:%S" hms+ <> formatTime defaultTimeLocale "%z" tz+instance Inline TimeOfDay where+ inline (TimeOfDay hr mn sc) = inferredtype $ makeTime+ (fromIntegral hr :* fromIntegral mn *: fromRational (toRational sc))+instance Inline LocalTime where+ inline (LocalTime day t) =+ let+ (y,m,d) = toGregorian day+ TimeOfDay hr mn sc = t+ in inferredtype $ makeTimestamp+ ( fromInteger y :* fromIntegral m :* fromIntegral d+ :* fromIntegral hr :* fromIntegral mn *: fromRational (toRational sc) )+instance Inline (Range Int32) where+ inline = range int4range . fmap inline+instance Inline (Range Int64) where+ inline = range int8range . fmap inline+instance Inline (Range Scientific) where+ inline = range numrange . fmap inline+instance Inline (Range LocalTime) where+ inline = range tsrange . fmap inline+instance Inline (Range UTCTime) where+ inline = range tstzrange . fmap inline+instance Inline (Range Day) where+ inline = range daterange . fmap inline+instance Inline UUID where+ inline+ = inferredtype+ . UnsafeExpression+ . singleQuotedUtf8+ . toASCIIBytes+instance Inline Money where+ inline moolah = inferredtype . UnsafeExpression $+ fromString (show dollars)+ <> "." <> fromString (show pennies)+ where+ (dollars,pennies) = cents moolah `divMod` 100+instance InlineParam x (NullPG x)+ => Inline (VarArray [x]) where+ inline (VarArray xs) = array (inlineParam <$> xs)+instance InlineParam x (NullPG x)+ => Inline (VarArray (Vector x)) where+ inline (VarArray xs) = array (inlineParam <$> toList xs)+instance Inline Oid where+ inline (Oid o) = inferredtype . UnsafeExpression . fromString $ show o+instance+ ( SOP.IsEnumType x+ , SOP.HasDatatypeInfo x+ ) => Inline (Enumerated x) where+ inline =+ let+ gshowConstructor+ :: NP SOP.ConstructorInfo xss+ -> SOP.SOP SOP.I xss+ -> String+ gshowConstructor Nil _ = ""+ gshowConstructor (constructor :* _) (SOP.SOP (SOP.Z _)) =+ SOP.constructorName constructor+ gshowConstructor (_ :* constructors) (SOP.SOP (SOP.S xs)) =+ gshowConstructor constructors (SOP.SOP xs)+ in+ UnsafeExpression+ . singleQuotedUtf8+ . fromString+ . gshowConstructor+ (SOP.constructorInfo (SOP.datatypeInfo (SOP.Proxy @x)))+ . SOP.from+ . getEnumerated+instance+ ( SOP.IsRecord x xs+ , SOP.AllZip InlineField xs (RowPG x)+ ) => Inline (Composite x) where+ inline+ = row+ . SOP.htrans (SOP.Proxy @InlineField) inlineField+ . SOP.toRecord+ . getComposite++-- | Lifts `Inline` to `NullType`s.+class InlineParam x ty where inlineParam :: x -> Expr ty+instance (Inline x, pg ~ PG x) => InlineParam x ('NotNull pg) where inlineParam = inline+instance (Inline x, pg ~ PG x) => InlineParam (Maybe x) ('Null pg) where+ inlineParam = maybe null_ inline++-- | Lifts `Inline` to fields.+class InlineField+ (field :: (Symbol, Type))+ (fieldpg :: (Symbol, NullType)) where+ inlineField+ :: SOP.P field+ -> Aliased (Expression grp lat with db params from) fieldpg+instance (KnownSymbol alias, InlineParam x ty)+ => InlineField (alias ::: x) (alias ::: ty) where+ inlineField (SOP.P x) = inlineParam x `as` Alias @alias++-- | Use a Haskell record as a inline a row of expressions.+inlineFields+ :: ( SOP.IsRecord hask fields+ , SOP.AllZip InlineField fields row )+ => hask -- ^ record+ -> NP (Aliased (Expression 'Ungrouped '[] with db params '[])) row+inlineFields+ = SOP.htrans (SOP.Proxy @InlineField) inlineField+ . SOP.toRecord+++-- | Lifts `Inline` to a column entry+class InlineColumn+ (field :: (Symbol, Type))+ (column :: (Symbol, ColumnType)) where+ -- | Haskell record field as a inline column+ inlineColumn+ :: SOP.P field+ -> Aliased (Optional (Expression grp lat with db params from)) column+instance (KnownSymbol col, InlineParam x ty)+ => InlineColumn (col ::: x) (col ::: 'NoDef :=> ty) where+ inlineColumn (SOP.P x) = Set (inlineParam x) `as` (Alias @col)+instance (KnownSymbol col, InlineParam x ty)+ => InlineColumn+ (col ::: Optional SOP.I ('Def :=> x))+ (col ::: 'Def :=> ty) where+ inlineColumn (SOP.P optional) = case optional of+ Default -> Default `as` (Alias @col)+ Set (SOP.I x) -> Set (inlineParam x) `as` (Alias @col)++-- | Use a Haskell record as a inline list of columns+inlineColumns+ :: ( SOP.IsRecord hask xs+ , SOP.AllZip InlineColumn xs columns )+ => hask -- ^ record+ -> NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns+inlineColumns+ = SOP.htrans (SOP.Proxy @InlineColumn) inlineColumn+ . SOP.toRecord
src/Squeal/PostgreSQL/Expression/Json.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Json-Description: Json and Jsonb functions and operators+Description: json and jsonb functions and operators Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Json and Jsonb functions and operators+json and jsonb functions and operators -} {-# LANGUAGE@@ -25,18 +25,18 @@ #-} module Squeal.PostgreSQL.Expression.Json- ( -- * Json and Jsonb operators+ ( -- * Json and Jsonb Operators (.->) , (.->>) , (.#>) , (.#>>)- -- * Jsonb operators+ -- * Jsonb Operators , (.?) , (.?|) , (.?&) , (.-.) , (#-.)- -- * Json and Jsonb functions+ -- * Json and Jsonb Functions , toJson , toJsonb , arrayToJson@@ -57,7 +57,7 @@ , jsonbSet , jsonbInsert , jsonbPretty- -- * Json and Jsonb set returning functions+ -- * Json and Jsonb Set Functions , jsonEach , jsonbEach , jsonEachText@@ -79,14 +79,14 @@ import Data.ByteString (ByteString) import GHC.TypeLits -import Squeal.PostgreSQL.Alias+import Squeal.PostgreSQL.Type.Alias import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Expression.SetOf import Squeal.PostgreSQL.Expression.Type-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Query.From+import Squeal.PostgreSQL.Query.From.Set import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema import qualified Generics.SOP as SOP @@ -188,7 +188,7 @@ -- otherwise, a scalar value is produced. For any scalar type other than a -- number, a Boolean, or a null value, the text representation will be used, in -- such a fashion that it is a valid json value.-toJson :: null ty :--> null 'PGjson+toJson :: null ty --> null 'PGjson toJson = unsafeFunction "to_json" -- | Returns the value as jsonb. Arrays and composites are converted@@ -197,26 +197,26 @@ -- otherwise, a scalar value is produced. For any scalar type other than a -- number, a Boolean, or a null value, the text representation will be used, in -- such a fashion that it is a valid jsonb value.-toJsonb :: null ty :--> null 'PGjsonb+toJsonb :: null ty --> null 'PGjsonb toJsonb = unsafeFunction "to_jsonb" -- | Returns the array as a JSON array. A PostgreSQL multidimensional array -- becomes a JSON array of arrays.-arrayToJson :: null ('PGvararray ty) :--> null 'PGjson+arrayToJson :: null ('PGvararray ty) --> null 'PGjson arrayToJson = unsafeFunction "array_to_json" -- | Returns the row as a JSON object.-rowToJson :: null ('PGcomposite ty) :--> null 'PGjson+rowToJson :: null ('PGcomposite ty) --> null 'PGjson rowToJson = unsafeFunction "row_to_json" -- | Builds a possibly-heterogeneously-typed JSON array out of a variadic -- argument list.-jsonBuildArray :: SOP.SListI tuple => FunctionN tuple (null 'PGjson)+jsonBuildArray :: SOP.SListI tuple => tuple ---> null 'PGjson jsonBuildArray = unsafeFunctionN "json_build_array" -- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a -- variadic argument list.-jsonbBuildArray :: SOP.SListI tuple => FunctionN tuple (null 'PGjsonb)+jsonbBuildArray :: SOP.SListI tuple => tuple ---> null 'PGjsonb jsonbBuildArray = unsafeFunctionN "jsonb_build_array" -- | Builds a possibly-heterogeneously-typed JSON object out of a variadic@@ -224,10 +224,10 @@ -- and values. class SOP.SListI tys => JsonBuildObject tys where - jsonBuildObject :: FunctionN tys (null 'PGjson)+ jsonBuildObject :: tys ---> null 'PGjson jsonBuildObject = unsafeFunctionN "json_build_object" - jsonbBuildObject :: FunctionN tys (null 'PGjsonb)+ jsonbBuildObject :: tys ---> null 'PGjsonb jsonbBuildObject = unsafeFunctionN "jsonb_build_object" instance JsonBuildObject '[]@@ -240,7 +240,7 @@ -- which are taken as a key/value pair. jsonObject :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))- :--> null 'PGjson+ --> null 'PGjson jsonObject = unsafeFunction "json_object" -- | Builds a binary JSON object out of a text array.@@ -249,24 +249,24 @@ -- which are taken as a key/value pair. jsonbObject :: null ('PGfixarray '[n,2] ('NotNull 'PGtext))- :--> null 'PGjsonb+ --> null 'PGjsonb jsonbObject = unsafeFunction "jsonb_object" -- | This is an alternate form of 'jsonObject' that takes two arrays; one for -- keys and one for values, that are zipped pairwise to create a JSON object.-jsonZipObject :: FunctionN+jsonZipObject :: '[ null ('PGvararray ('NotNull 'PGtext)) , null ('PGvararray ('NotNull 'PGtext)) ]- ( null 'PGjson )+ ---> null 'PGjson jsonZipObject = unsafeFunctionN "json_object" -- | This is an alternate form of 'jsonbObject' that takes two arrays; one for -- keys and one for values, that are zipped pairwise to create a binary JSON -- object.-jsonbZipObject :: FunctionN+jsonbZipObject :: '[ null ('PGvararray ('NotNull 'PGtext)) , null ('PGvararray ('NotNull 'PGtext)) ]- ( null 'PGjsonb )+ ---> null 'PGjsonb jsonbZipObject = unsafeFunctionN "jsonb_object" {-----------------------------------------@@ -274,31 +274,31 @@ -----------------------------------------} -- | Returns the number of elements in the outermost JSON array.-jsonArrayLength :: null 'PGjson :--> null 'PGint4+jsonArrayLength :: null 'PGjson --> null 'PGint4 jsonArrayLength = unsafeFunction "json_array_length" -- | Returns the number of elements in the outermost binary JSON array.-jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4+jsonbArrayLength :: null 'PGjsonb --> null 'PGint4 jsonbArrayLength = unsafeFunction "jsonb_array_length" -- | Returns the type of the outermost JSON value as a text string. Possible -- types are object, array, string, number, boolean, and null.-jsonTypeof :: null 'PGjson :--> null 'PGtext+jsonTypeof :: null 'PGjson --> null 'PGtext jsonTypeof = unsafeFunction "json_typeof" -- | Returns the type of the outermost binary JSON value as a text string. -- Possible types are object, array, string, number, boolean, and null.-jsonbTypeof :: null 'PGjsonb :--> null 'PGtext+jsonbTypeof :: null 'PGjsonb --> null 'PGtext jsonbTypeof = unsafeFunction "jsonb_typeof" -- | Returns its argument with all object fields that have null values omitted. -- Other null values are untouched.-jsonStripNulls :: null 'PGjson :--> null 'PGjson+jsonStripNulls :: null 'PGjson --> null 'PGjson jsonStripNulls = unsafeFunction "json_strip_nulls" -- | Returns its argument with all object fields that have null values omitted. -- Other null values are untouched.-jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb+jsonbStripNulls :: null 'PGjsonb --> null 'PGjsonb jsonbStripNulls = unsafeFunction "jsonb_strip_nulls" -- | @ jsonbSet target path new_value create_missing @@@ -309,12 +309,9 @@ -- item designated by path does not exist. As with the path orientated -- operators, negative integers that appear in path count from the end of JSON -- arrays.-jsonbSet- :: FunctionN- '[ null 'PGjsonb- , null ('PGvararray ('NotNull 'PGtext))- , null 'PGjsonb- , null 'PGbool ] (null 'PGjsonb)+jsonbSet ::+ '[ null 'PGjsonb, null ('PGvararray ('NotNull 'PGtext))+ , null 'PGjsonb, null 'PGbool ] ---> null 'PGjsonb jsonbSet = unsafeFunctionN "jsonbSet" -- | @ jsonbInsert target path new_value insert_after @@@ -326,86 +323,82 @@ -- path is in JSONB object, @new_value@ will be inserted only if target does not -- exist. As with the path orientated operators, negative integers that appear -- in path count from the end of JSON arrays.-jsonbInsert- :: FunctionN- '[ null 'PGjsonb- , null ('PGvararray ('NotNull 'PGtext))- , null 'PGjsonb- , null 'PGbool ] (null 'PGjsonb)+jsonbInsert ::+ '[ null 'PGjsonb, null ('PGvararray ('NotNull 'PGtext))+ , null 'PGjsonb, null 'PGbool ] ---> null 'PGjsonb jsonbInsert = unsafeFunctionN "jsonb_insert" -- | Returns its argument as indented JSON text.-jsonbPretty :: null 'PGjsonb :--> null 'PGtext+jsonbPretty :: null 'PGjsonb --> null 'PGtext jsonbPretty = unsafeFunction "jsonb_pretty" - {- | Expands the outermost JSON object into a set of key/value pairs. ->>> printSQL (select Star (from (jsonEach (literal (Json (object ["a" .= "foo", "b" .= "bar"]))))))+>>> printSQL (select Star (from (jsonEach (inline (Json (object ["a" .= "foo", "b" .= "bar"])))))) SELECT * FROM json_each(('{"a":"foo","b":"bar"}' :: json)) -}-jsonEach :: SetOfFunction "json_each" (null 'PGjson)- '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]-jsonEach = unsafeSetOfFunction+jsonEach :: null 'PGjson -|->+ ("json_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson])+jsonEach = unsafeSetFunction "json_each" {- | Expands the outermost binary JSON object into a set of key/value pairs. ->>> printSQL (select Star (from (jsonbEach (literal (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))))+>>> printSQL (select Star (from (jsonbEach (inline (Jsonb (object ["a" .= "foo", "b" .= "bar"])))))) SELECT * FROM jsonb_each(('{"a":"foo","b":"bar"}' :: jsonb)) -} jsonbEach- :: SetOfFunction "jsonb_each" (nullity 'PGjsonb)- '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]-jsonbEach = unsafeSetOfFunction+ :: null 'PGjsonb -|->+ ("jsonb_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson])+jsonbEach = unsafeSetFunction "jsonb_each" {- | Expands the outermost JSON object into a set of key/value pairs. ->>> printSQL (select Star (from (jsonEachText (literal (Json (object ["a" .= "foo", "b" .= "bar"]))))))+>>> printSQL (select Star (from (jsonEachText (inline (Json (object ["a" .= "foo", "b" .= "bar"])))))) SELECT * FROM json_each_text(('{"a":"foo","b":"bar"}' :: json)) -} jsonEachText- :: SetOfFunction "json_each_text" (null 'PGjson)- '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]-jsonEachText = unsafeSetOfFunction+ :: null 'PGjson -|->+ ("json_each_text" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext])+jsonEachText = unsafeSetFunction "json_each_text" {- | Expands the outermost binary JSON object into a set of key/value pairs. ->>> printSQL (select Star (from (jsonbEachText (literal (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))))+>>> printSQL (select Star (from (jsonbEachText (inline (Jsonb (object ["a" .= "foo", "b" .= "bar"])))))) SELECT * FROM jsonb_each_text(('{"a":"foo","b":"bar"}' :: jsonb)) -} jsonbEachText- :: SetOfFunction "jsonb_each_text" (null 'PGjsonb)- '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]-jsonbEachText = unsafeSetOfFunction+ :: null 'PGjsonb -|->+ ("jsonb_each_text" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext])+jsonbEachText = unsafeSetFunction "jsonb_each_text" {- | Returns set of keys in the outermost JSON object. ->>> printSQL (jsonObjectKeys (literal (Json (object ["a" .= "foo", "b" .= "bar"]))))+>>> printSQL (jsonObjectKeys (inline (Json (object ["a" .= "foo", "b" .= "bar"])))) json_object_keys(('{"a":"foo","b":"bar"}' :: json)) -} jsonObjectKeys- :: SetOfFunction "json_object_keys" (nullity 'PGjson)- '["json_object_keys" ::: 'NotNull 'PGtext]-jsonObjectKeys = unsafeSetOfFunction+ :: null 'PGjson -|->+ ("json_object_keys" ::: '["json_object_keys" ::: 'NotNull 'PGtext])+jsonObjectKeys = unsafeSetFunction "json_object_keys" {- | Returns set of keys in the outermost JSON object. ->>> printSQL (jsonbObjectKeys (literal (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))+>>> printSQL (jsonbObjectKeys (inline (Jsonb (object ["a" .= "foo", "b" .= "bar"])))) jsonb_object_keys(('{"a":"foo","b":"bar"}' :: jsonb)) -} jsonbObjectKeys- :: SetOfFunction "jsonb_object_keys" (null 'PGjsonb)- '["jsonb_object_keys" ::: 'NotNull 'PGtext]-jsonbObjectKeys = unsafeSetOfFunction+ :: null 'PGjsonb -|->+ ("jsonb_object_keys" ::: '["jsonb_object_keys" ::: 'NotNull 'PGtext])+jsonbObjectKeys = unsafeSetFunction "jsonb_object_keys" -- | Build rows from Json types. type JsonPopulateFunction fun json- = forall schemas row outer commons params+ = forall db row lat with params . json `In` PGJsonType- => TypeExpression schemas ('NotNull ('PGcomposite row)) -- ^ row type- -> Expression outer commons 'Ungrouped schemas params '[] ('NotNull json)+ => TypeExpression db ('NotNull ('PGcomposite row)) -- ^ row type+ -> Expression 'Ungrouped lat with db params '[] ('NotNull json) -- ^ json type- -> FromClause outer commons schemas params '[fun ::: row]+ -> FromClause lat with db params '[fun ::: row] unsafePopulateFunction :: forall fun ty@@ -436,20 +429,20 @@ -- | Build rows from Json types. type JsonToRecordFunction json- = forall outer commons schemas params tab row+ = forall lat with db params tab row . (SOP.SListI row, json `In` PGJsonType)- => Expression outer commons 'Ungrouped schemas params '[] ('NotNull json)+ => Expression 'Ungrouped lat with db params '[] ('NotNull json) -- ^ json type- -> Aliased (NP (Aliased (TypeExpression schemas))) (tab ::: row)+ -> Aliased (NP (Aliased (TypeExpression db))) (tab ::: row) -- ^ row type- -> FromClause outer commons schemas params '[tab ::: row]+ -> FromClause lat with db params '[tab ::: row] unsafeRecordFunction :: ByteString -> JsonToRecordFunction json unsafeRecordFunction fun expr (types `As` tab) = UnsafeFromClause $ fun <> parenthesized (renderSQL expr) <+> "AS" <+> renderSQL tab <> parenthesized (renderCommaSeparated renderTy types) where- renderTy :: Aliased (TypeExpression schemas) ty -> ByteString+ renderTy :: Aliased (TypeExpression db) ty -> ByteString renderTy (ty `As` alias) = renderSQL alias <+> renderSQL ty -- | Builds an arbitrary record from a JSON object.
− src/Squeal/PostgreSQL/Expression/Literal.hs
@@ -1,87 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Expression.Literal-Description: Literal expressions-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--Literal expressions--}--{-# LANGUAGE- FlexibleContexts- , FlexibleInstances- , LambdaCase- , OverloadedStrings- , RankNTypes- , ScopedTypeVariables- , TypeApplications- , TypeSynonymInstances- , UndecidableInstances-#-}--module Squeal.PostgreSQL.Expression.Literal (Literal (..)) where--import ByteString.StrictBuilder (builderBytes)-import Data.ByteString.Lazy (toStrict)-import Data.Int-import Data.String-import Data.Text (Text)--import qualified Data.Aeson as JSON-import qualified Data.Text as Text-import qualified Data.Text.Lazy as Lazy (Text)-import qualified Data.Text.Lazy as Lazy.Text--import Squeal.PostgreSQL.Binary-import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Expression.Logic-import Squeal.PostgreSQL.PG-import Squeal.PostgreSQL.Render--{- |-The `Literal` class allows embedding a Haskell value directly-as an `Expression` using `literal`.-->>> printSQL (literal 'a')-E'a'-->>> printSQL (literal (1 :: Double))-1.0-->>> printSQL (literal (Json [1 :: Double, 2]))-('[1.0,2.0]' :: json)-->>> printSQL (literal (Enumerated GT))-'GT'--}-class Literal hask where literal :: hask -> Expr (null (PG hask))-instance Literal Bool where- literal = \case- True -> true- False -> false-instance JSON.ToJSON hask => Literal (Json hask) where- literal = UnsafeExpression . parenthesized . (<> " :: json")- . singleQuotedUtf8 . toStrict . JSON.encode . getJson-instance JSON.ToJSON hask => Literal (Jsonb hask) where- literal = UnsafeExpression . parenthesized . (<> " :: jsonb")- . singleQuotedUtf8 . toStrict . JSON.encode . getJsonb-instance Literal Char where- literal chr = UnsafeExpression $- "E\'" <> fromString (escape chr) <> "\'"-instance Literal String where literal = fromString-instance Literal Int16 where literal = fromIntegral-instance Literal Int32 where literal = fromIntegral-instance Literal Int64 where literal = fromIntegral-instance Literal Float where literal = fromRational . toRational-instance Literal Double where literal = fromRational . toRational-instance Literal Text where literal = fromString . Text.unpack-instance Literal Lazy.Text where literal = fromString . Lazy.Text.unpack-instance ToParam (Enumerated enum) (PG (Enumerated enum))- => Literal (Enumerated enum) where- literal- = UnsafeExpression- . singleQuotedUtf8- . builderBytes- . unK- . toParam @(Enumerated enum) @(PG (Enumerated enum))
src/Squeal/PostgreSQL/Expression/Logic.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Logic-Description: Logical expressions+Description: logical expressions and operators Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Logical expressions and operators+logical expressions and operators -} {-# LANGUAGE@@ -15,25 +15,28 @@ #-} module Squeal.PostgreSQL.Expression.Logic- ( Condition+ ( -- * Condition+ Condition , true , false+ -- * Logic , not_ , (.&&) , (.||)+ -- * Conditional , caseWhenThenElse , ifThenElse ) where import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- | A `Condition` is an `Expression`, which can evaluate -- to `true`, `false` or `Squeal.PostgreSQL.Null.null_`. This is because SQL uses -- a three valued logic.-type Condition outer commons grp schemas params from =- Expression outer commons grp schemas params from ('Null 'PGbool)+type Condition grp lat with db params from =+ Expression grp lat with db params from ('Null 'PGbool) -- | >>> printSQL true -- TRUE@@ -47,8 +50,8 @@ -- | >>> printSQL $ not_ true -- (NOT TRUE)-not_ :: null 'PGbool :--> null 'PGbool-not_ = unsafeUnaryOpL "NOT"+not_ :: null 'PGbool --> null 'PGbool+not_ = unsafeLeftOp "NOT" -- | >>> printSQL $ true .&& false -- (TRUE AND FALSE)@@ -64,19 +67,19 @@ -- | >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGint2)+-- expression :: Expression grp lat with db params from (null 'PGint2) -- expression = caseWhenThenElse [(true, 1), (false, 2)] 3 -- in printSQL expression -- :}--- CASE WHEN TRUE THEN 1 WHEN FALSE THEN 2 ELSE 3 END+-- CASE WHEN TRUE THEN (1 :: int2) WHEN FALSE THEN (2 :: int2) ELSE (3 :: int2) END caseWhenThenElse- :: [ ( Condition outer commons grp schemas params from- , Expression outer commons grp schemas params from ty+ :: [ ( Condition grp lat with db params from+ , Expression grp lat with db params from ty ) ] -- ^ whens and thens- -> Expression outer commons grp schemas params from ty+ -> Expression grp lat with db params from ty -- ^ else- -> Expression outer commons grp schemas params from ty+ -> Expression grp lat with db params from ty caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat [ "CASE" , mconcat@@ -92,14 +95,14 @@ -- | >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGint2)+-- expression :: Expression grp lat with db params from (null 'PGint2) -- expression = ifThenElse true 1 0 -- in printSQL expression -- :}--- CASE WHEN TRUE THEN 1 ELSE 0 END+-- CASE WHEN TRUE THEN (1 :: int2) ELSE (0 :: int2) END ifThenElse- :: Condition outer commons grp schemas params from- -> Expression outer commons grp schemas params from ty -- ^ then- -> Expression outer commons grp schemas params from ty -- ^ else- -> Expression outer commons grp schemas params from ty+ :: Condition grp lat with db params from+ -> Expression grp lat with db params from ty -- ^ then+ -> Expression grp lat with db params from ty -- ^ else+ -> Expression grp lat with db params from ty ifThenElse if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
src/Squeal/PostgreSQL/Expression/Math.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Math-Description: Math expressions+Description: math functions Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Mathematical functions and operators+math functions -} {-# LANGUAGE@@ -15,7 +15,8 @@ #-} module Squeal.PostgreSQL.Expression.Math- ( atan2_+ ( -- * Math Function+ atan2_ , quot_ , rem_ , trunc@@ -24,8 +25,8 @@ ) where import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -36,10 +37,8 @@ -- expression = atan2_ (pi *: 2) -- in printSQL expression -- :}--- atan2(pi(), 2)-atan2_- :: float `In` PGFloating- => FunctionN '[ null float, null float] (null float)+-- atan2(pi(), (2.0 :: float4))+atan2_ :: float `In` PGFloating => '[ null float, null float] ---> null float atan2_ = unsafeFunctionN "atan2" @@ -47,11 +46,11 @@ -- -- >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGint2)+-- expression :: Expression grp lat with db params from (null 'PGint2) -- expression = 5 `quot_` 2 -- in printSQL expression -- :}--- (5 / 2)+-- ((5 :: int2) / (2 :: int2)) quot_ :: int `In` PGIntegral => Operator (null int) (null int) (null int)@@ -61,11 +60,11 @@ -- -- >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGint2)+-- expression :: Expression grp lat with db params from (null 'PGint2) -- expression = 5 `rem_` 2 -- in printSQL expression -- :}--- (5 % 2)+-- ((5 :: int2) % (2 :: int2)) rem_ :: int `In` PGIntegral => Operator (null int) (null int) (null int)@@ -73,30 +72,30 @@ -- | >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)+-- expression :: Expression grp lat with db params from (null 'PGfloat4) -- expression = trunc pi -- in printSQL expression -- :} -- trunc(pi())-trunc :: frac `In` PGFloating => null frac :--> null frac+trunc :: frac `In` PGFloating => null frac --> null frac trunc = unsafeFunction "trunc" -- | >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)+-- expression :: Expression grp lat with db params from (null 'PGfloat4) -- expression = round_ pi -- in printSQL expression -- :} -- round(pi())-round_ :: frac `In` PGFloating => null frac :--> null frac+round_ :: frac `In` PGFloating => null frac --> null frac round_ = unsafeFunction "round" -- | >>> :{ -- let--- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)+-- expression :: Expression grp lat with db params from (null 'PGfloat4) -- expression = ceiling_ pi -- in printSQL expression -- :} -- ceiling(pi())-ceiling_ :: frac `In` PGFloating => null frac :--> null frac+ceiling_ :: frac `In` PGFloating => null frac --> null frac ceiling_ = unsafeFunction "ceiling"
src/Squeal/PostgreSQL/Expression/Null.hs view
@@ -1,22 +1,26 @@ {-| Module: Squeal.PostgreSQL.Expression.Null-Description: Null+Description: null expressions and handlers Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Null values and null handling functions+null expressions and handlers -} {-# LANGUAGE DataKinds , OverloadedStrings+ , RankNTypes , TypeOperators #-} module Squeal.PostgreSQL.Expression.Null- ( null_+ ( -- * Null+ null_ , notNull+ , unsafeNotNull+ , monoNotNull , coalesce , fromNull , isNull@@ -28,7 +32,7 @@ import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Expression.Logic import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -44,14 +48,29 @@ -- -- >>> printSQL $ notNull true -- TRUE-notNull :: 'NotNull ty :--> 'Null ty+notNull :: 'NotNull ty --> 'Null ty notNull = UnsafeExpression . renderSQL +-- | Analagous to `Data.Maybe.fromJust` inverse to `notNull`,+-- useful when you know an `Expression` is `NotNull`,+-- because, for instance, you've filtered out @NULL@+-- values in a column.+unsafeNotNull :: 'Null ty --> 'NotNull ty+unsafeNotNull = UnsafeExpression . renderSQL++-- | Some expressions are null polymorphic which may raise+-- inference issues. Use `monoNotNull` to fix their+-- nullity as `NotNull`.+monoNotNull+ :: (forall null. Expression grp lat with db params from (null ty))+ -> Expression grp lat with db params from ('NotNull ty)+monoNotNull = id+ -- | return the leftmost value which is not NULL -- -- >>> printSQL $ coalesce [null_, true] false -- COALESCE(NULL, TRUE, FALSE)-coalesce :: FunctionVar ('Null ty) ('NotNull ty) ('NotNull ty)+coalesce :: FunctionVar ('Null ty) (null ty) (null ty) coalesce nullxs notNullx = UnsafeExpression $ "COALESCE" <> parenthesized (commaSeparated ((renderSQL <$> nullxs) <> [renderSQL notNullx]))@@ -61,20 +80,20 @@ -- >>> printSQL $ fromNull true null_ -- COALESCE(NULL, TRUE) fromNull- :: Expression outer commons grp schemas params from ('NotNull ty)+ :: Expression grp lat with db params from ('NotNull ty) -- ^ what to convert @NULL@ to- -> Expression outer commons grp schemas params from ('Null ty)- -> Expression outer commons grp schemas params from ('NotNull ty)+ -> Expression grp lat with db params from ('Null ty)+ -> Expression grp lat with db params from ('NotNull ty) fromNull notNullx nullx = coalesce [nullx] notNullx -- | >>> printSQL $ null_ & isNull -- NULL IS NULL-isNull :: 'Null ty :--> null 'PGbool+isNull :: 'Null ty --> null 'PGbool isNull x = UnsafeExpression $ renderSQL x <+> "IS NULL" -- | >>> printSQL $ null_ & isNotNull -- NULL IS NOT NULL-isNotNull :: 'Null ty :--> null 'PGbool+isNotNull :: 'Null ty --> null 'PGbool isNotNull x = UnsafeExpression $ renderSQL x <+> "IS NOT NULL" -- | analagous to `maybe` using @IS NULL@@@ -82,13 +101,13 @@ -- >>> printSQL $ matchNull true not_ null_ -- CASE WHEN NULL IS NULL THEN TRUE ELSE (NOT NULL) END matchNull- :: Expression outer commons grp schemas params from (nullty)+ :: Expression grp lat with db params from (nullty) -- ^ what to convert @NULL@ to- -> ( Expression outer commons grp schemas params from ('NotNull ty)- -> Expression outer commons grp schemas params from (nullty) )+ -> ( Expression grp lat with db params from ('NotNull ty)+ -> Expression grp lat with db params from (nullty) ) -- ^ function to perform when @NULL@ is absent- -> Expression outer commons grp schemas params from ('Null ty)- -> Expression outer commons grp schemas params from (nullty)+ -> Expression grp lat with db params from ('Null ty)+ -> Expression grp lat with db params from (nullty) matchNull y f x = ifThenElse (isNull x) y (f (UnsafeExpression (renderSQL x))) @@ -96,9 +115,9 @@ `nullIf` gives @NULL@. >>> :set -XTypeApplications -XDataKinds->>> let expr = nullIf (false *: param @1) :: Expression outer commons grp schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)+>>> let expr = nullIf (false *: param @1) :: Expression grp lat with db '[ 'NotNull 'PGbool] from ('Null 'PGbool) >>> printSQL expr NULLIF(FALSE, ($1 :: bool)) -}-nullIf :: FunctionN '[ 'NotNull ty, 'NotNull ty] ('Null ty)+nullIf :: '[ 'NotNull ty, 'NotNull ty] ---> 'Null ty nullIf = unsafeFunctionN "NULLIF"
src/Squeal/PostgreSQL/Expression/Parameter.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Parameter-Description: Parameters+Description: out-of-line parameters Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Parameters, out-of-line data values+out-of-line parameters -} {-# LANGUAGE@@ -25,7 +25,8 @@ #-} module Squeal.PostgreSQL.Expression.Parameter- ( HasParameter (parameter)+ ( -- * Parameter+ HasParameter (parameter) , param ) where @@ -34,32 +35,32 @@ import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Expression.Type import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL {- | A `HasParameter` constraint is used to indicate a value that is supplied externally to a SQL statement.-`Squeal.PostgreSQL.PQ.manipulateParams`,-`Squeal.PostgreSQL.PQ.queryParams` and-`Squeal.PostgreSQL.PQ.traversePrepared` support specifying data values+`Squeal.PostgreSQL.Session.manipulateParams`,+`Squeal.PostgreSQL.Session.queryParams` and+`Squeal.PostgreSQL.Session.traversePrepared` support specifying data values separately from the SQL command string, in which case `param`s are used to refer to the out-of-line data values. -} class KnownNat n => HasParameter (n :: Nat)- (params :: [NullityType])- (ty :: NullityType)+ (params :: [NullType])+ (ty :: NullType) | n params -> ty where -- | `parameter` takes a `Nat` using type application and a `TypeExpression`. --- -- >>> let expr = parameter @1 int4 :: Expression outer '[] grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)+ -- >>> let expr = parameter @1 int4 :: Expression lat '[] grp db '[ 'Null 'PGint4] from ('Null 'PGint4) -- >>> printSQL expr -- ($1 :: int4) parameter- :: TypeExpression schemas ty- -> Expression outer commons grp schemas params from ty+ :: TypeExpression db ty+ -> Expression grp lat with db params from ty parameter ty = UnsafeExpression $ parenthesized $ "$" <> renderNat @n <+> "::" <+> renderSQL ty@@ -70,11 +71,11 @@ -- | `param` takes a `Nat` using type application and for basic types, -- infers a `TypeExpression`. ----- >>> let expr = param @1 :: Expression outer commons grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)+-- >>> let expr = param @1 :: Expression grp lat with db '[ 'Null 'PGint4] from ('Null 'PGint4) -- >>> printSQL expr -- ($1 :: int4) param- :: forall n outer commons schemas params from grp ty- . (PGTyped schemas ty, HasParameter n params ty)- => Expression outer commons grp schemas params from ty -- ^ param-param = parameter @n (pgtype @schemas)+ :: forall n ty lat with db params from grp+ . (NullTyped db ty, HasParameter n params ty)+ => Expression grp lat with db params from ty -- ^ param+param = parameter @n (nulltype @db)
+ src/Squeal/PostgreSQL/Expression/Range.hs view
@@ -0,0 +1,227 @@+{-|+Module: Squeal.PostgreSQL.Expression.Range+Description: range types and functions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++range types and functions+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , DataKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DeriveFoldable+ , DerivingStrategies+ , DeriveTraversable+ , FlexibleContexts+ , FlexibleInstances+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , PatternSynonyms+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Expression.Range+ ( -- * Range+ Range (..)+ , (<=..<=), (<..<), (<=..<), (<..<=)+ , moreThan, atLeast, lessThan, atMost+ , singleton, whole+ , Bound (..)+ -- * Range Function+ -- ** Range Construction+ , range+ -- ** Range Operator+ , (.<@)+ , (@>.)+ , (<<@)+ , (@>>)+ , (&<)+ , (&>)+ , (-|-)+ , (@+)+ , (@*)+ , (@-)+ -- ** Range Function+ , lowerBound+ , upperBound+ , isEmpty+ , lowerInc+ , lowerInf+ , upperInc+ , upperInf+ , rangeMerge+ ) where++import qualified GHC.Generics as GHC+import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Type hiding (bool)+import Squeal.PostgreSQL.Type.PG+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL (tstzrange, numrange, int4range, now, printSQL)++-- | Construct a `range`+--+-- >>> printSQL $ range tstzrange (atLeast now)+-- tstzrange(now(), NULL, '[)')+-- >>> printSQL $ range numrange (0 <=..< 2*pi)+-- numrange((0.0 :: numeric), ((2.0 :: numeric) * pi()), '[)')+-- >>> printSQL $ range int4range Empty+-- ('empty' :: int4range)+range+ :: TypeExpression db (null ('PGrange ty))+ -- ^ range type+ -> Range (Expression grp lat with db params from ('NotNull ty))+ -- ^ range of values+ -> Expression grp lat with db params from (null ('PGrange ty))+range ty = \case+ Empty -> UnsafeExpression $ parenthesized+ (emp <+> "::" <+> renderSQL ty)+ NonEmpty l u -> UnsafeExpression $ renderSQL ty <> parenthesized+ (commaSeparated (args l u))+ where+ emp = singleQuote <> "empty" <> singleQuote+ args l u = [arg l, arg u, singleQuote <> bra l <> ket u <> singleQuote]+ singleQuote = "\'"+ arg = \case+ Infinite -> "NULL"; Closed x -> renderSQL x; Open x -> renderSQL x+ bra = \case Infinite -> "("; Closed _ -> "["; Open _ -> "("+ ket = \case Infinite -> ")"; Closed _ -> "]"; Open _ -> ")"++-- | The type of `Bound` for a `Range`.+data Bound x+ = Infinite -- ^ unbounded+ | Closed x -- ^ inclusive+ | Open x -- ^ exclusive+ deriving+ ( Eq, Ord, Show, Read, GHC.Generic+ , Functor, Foldable, Traversable )++-- | A `Range` datatype that comprises connected subsets of+-- the real line.+data Range x = Empty | NonEmpty (Bound x) (Bound x)+ deriving+ ( Eq, Ord, Show, Read, GHC.Generic+ , Functor, Foldable, Traversable )+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)+-- | `PGrange` @(@`PG` @hask)@+instance IsPG hask => IsPG (Range hask) where+ type PG (Range hask) = 'PGrange (PG hask)++-- | Finite `Range` constructor+(<=..<=), (<..<), (<=..<), (<..<=) :: x -> x -> Range x+infix 4 <=..<=, <..<, <=..<, <..<=+x <=..<= y = NonEmpty (Closed x) (Closed y)+x <..< y = NonEmpty (Open x) (Open y)+x <=..< y = NonEmpty (Closed x) (Open y)+x <..<= y = NonEmpty (Open x) (Closed y)++-- | Half-infinite `Range` constructor+moreThan, atLeast, lessThan, atMost :: x -> Range x+moreThan x = NonEmpty (Open x) Infinite+atLeast x = NonEmpty (Closed x) Infinite+lessThan x = NonEmpty Infinite (Open x)+atMost x = NonEmpty Infinite (Closed x)++-- | A point on the line+singleton :: x -> Range x+singleton x = x <=..<= x++-- | The `whole` line+whole :: Range x+whole = NonEmpty Infinite Infinite++-- | range is contained by+(.<@) :: Operator ('NotNull ty) (null ('PGrange ty)) ('Null 'PGbool)+(.<@) = unsafeBinaryOp "<@"++-- | contains range+(@>.) :: Operator (null ('PGrange ty)) ('NotNull ty) ('Null 'PGbool)+(@>.) = unsafeBinaryOp "<@"++-- | strictly left of,+-- return false when an empty range is involved+(<<@) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) ('Null 'PGbool)+(<<@) = unsafeBinaryOp "<<"++-- | strictly right of,+-- return false when an empty range is involved+(@>>) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) ('Null 'PGbool)+(@>>) = unsafeBinaryOp ">>"++-- | does not extend to the right of,+-- return false when an empty range is involved+(&<) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) ('Null 'PGbool)+(&<) = unsafeBinaryOp "&<"++-- | does not extend to the left of,+-- return false when an empty range is involved+(&>) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) ('Null 'PGbool)+(&>) = unsafeBinaryOp "&>"++-- | is adjacent to, return false when an empty range is involved+(-|-) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) ('Null 'PGbool)+(-|-) = unsafeBinaryOp "-|-"++-- | union, will fail if the resulting range would+-- need to contain two disjoint sub-ranges+(@+) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) (null ('PGrange ty))+(@+) = unsafeBinaryOp "+"++-- | intersection+(@*) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) (null ('PGrange ty))+(@*) = unsafeBinaryOp "*"++-- | difference, will fail if the resulting range would+-- need to contain two disjoint sub-ranges+(@-) :: Operator (null ('PGrange ty)) (null ('PGrange ty)) (null ('PGrange ty))+(@-) = unsafeBinaryOp "-"++-- | lower bound of range+lowerBound :: null ('PGrange ty) --> 'Null ty+lowerBound = unsafeFunction "lower"++-- | upper bound of range+upperBound :: null ('PGrange ty) --> 'Null ty+upperBound = unsafeFunction "upper"++-- | is the range empty?+isEmpty :: null ('PGrange ty) --> 'Null 'PGbool+isEmpty = unsafeFunction "isempty"++-- | is the lower bound inclusive?+lowerInc :: null ('PGrange ty) --> 'Null 'PGbool+lowerInc = unsafeFunction "lower_inc"++-- | is the lower bound infinite?+lowerInf :: null ('PGrange ty) --> 'Null 'PGbool+lowerInf = unsafeFunction "lower_inf"++-- | is the upper bound inclusive?+upperInc :: null ('PGrange ty) --> 'Null 'PGbool+upperInc = unsafeFunction "upper_inc"++-- | is the upper bound infinite?+upperInf :: null ('PGrange ty) --> 'Null 'PGbool+upperInf = unsafeFunction "upper_inf"++-- | the smallest range which includes both of the given ranges+rangeMerge ::+ '[null ('PGrange ty), null ('PGrange ty)]+ ---> null ('PGrange ty)+rangeMerge = unsafeFunctionN "range_merge"
− src/Squeal/PostgreSQL/Expression/SetOf.hs
@@ -1,106 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Expression.SetOf-Description: Set returning functions-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--Set returning functions--}--{-# LANGUAGE- AllowAmbiguousTypes- , DataKinds- , FlexibleContexts- , OverloadedStrings- , PolyKinds- , RankNTypes- , ScopedTypeVariables- , TypeApplications- , TypeOperators-#-}--module Squeal.PostgreSQL.Expression.SetOf- ( generateSeries- , generateSeriesStep- , generateSeriesTimestamp- , SetOfFunction- , unsafeSetOfFunction- , SetOfFunctionN- , unsafeSetOfFunctionN- ) where--import GHC.TypeLits--import qualified Generics.SOP as SOP--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Query-import Squeal.PostgreSQL.Schema--{- |-A @RankNType@ for set returning functions with 1 argument.--}-type SetOfFunction fun ty setof- = forall outer commons schemas params- . Expression outer commons 'Ungrouped schemas params '[] ty- -- ^ input- -> FromClause outer commons schemas params '[fun ::: setof]- -- ^ output---- | Escape hatch for a set returning function with 1 argument.-unsafeSetOfFunction- :: forall fun ty setof. KnownSymbol fun- => SetOfFunction fun ty setof -- ^ set returning function-unsafeSetOfFunction x = UnsafeFromClause $- renderSymbol @fun <> parenthesized (renderSQL x)--{- |-A @RankNType@ for set returning functions with multiple argument.--}-type SetOfFunctionN fun tys setof- = forall outer commons schemas params- . NP (Expression outer commons 'Ungrouped schemas params '[]) tys- -- ^ inputs- -> FromClause outer commons schemas params '[fun ::: setof]- -- ^ output---- | Escape hatch for a set returning function with multiple argument.-unsafeSetOfFunctionN- :: forall fun tys setof. (SOP.SListI tys, KnownSymbol fun)- => SetOfFunctionN fun tys setof -- ^ set returning function-unsafeSetOfFunctionN xs = UnsafeFromClause $- renderSymbol @fun <> parenthesized (renderCommaSeparated renderSQL xs)--{- | @generateSeries (start *: stop)@--Generate a series of values, from @start@ to @stop@ with a step size of one--}-generateSeries- :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric]- => SetOfFunctionN "generate_series" '[ null ty, null ty]- '["generate_series" ::: null ty] -- ^ set returning function-generateSeries = unsafeSetOfFunctionN--{- | @generateSeries (start :* stop *: step)@--Generate a series of values, from @start@ to @stop@ with a step size of @step@--}-generateSeriesStep- :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric]- => SetOfFunctionN "generate_series" '[null ty, null ty, null ty]- '["generate_series" ::: null ty] -- ^ set returning function-generateSeriesStep = unsafeSetOfFunctionN--{- | @generateSeries (start :* stop *: step)@--Generate a series of values, from @start@ to @stop@ with a step size of @step@--}-generateSeriesTimestamp- :: ty `In` '[ 'PGtimestamp, 'PGtimestamptz]- => SetOfFunctionN "generate_series" '[null ty, null ty, null 'PGinterval]- '["generate_series" ::: null ty] -- ^ set returning function-generateSeriesTimestamp = unsafeSetOfFunctionN
src/Squeal/PostgreSQL/Expression/Sort.hs view
@@ -1,29 +1,33 @@ {-| Module: Squeal.PostgreSQL.Expression.Sort-Description: Sort expressions+Description: sort expressions Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Sort expressions+sort expressions -} {-# LANGUAGE DataKinds+ , FlexibleInstances+ , FunctionalDependencies , GADTs , LambdaCase+ , MultiParamTypeClasses , OverloadedStrings , StandaloneDeriving #-} module Squeal.PostgreSQL.Expression.Sort- ( SortExpression (..)+ ( -- * Sort+ SortExpression (..) , OrderBy (..) ) where import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- | `SortExpression`s are used by `orderBy` to optionally sort the results -- of a `Squeal.PostgreSQL.Query.Query`. `Asc` or `Desc`@@ -36,27 +40,33 @@ -- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to -- determine whether nulls appear before or after non-null values in the sort -- ordering of a `Null` result column.-data SortExpression outer commons grp schemas params from where+data SortExpression grp lat with db params from where Asc- :: Expression outer commons grp schemas params from ('NotNull ty)- -> SortExpression outer commons grp schemas params from+ :: Expression grp lat with db params from ('NotNull ty)+ -- ^ sort by+ -> SortExpression grp lat with db params from Desc- :: Expression outer commons grp schemas params from ('NotNull ty)- -> SortExpression outer commons grp schemas params from+ :: Expression grp lat with db params from ('NotNull ty)+ -- ^ sort by+ -> SortExpression grp lat with db params from AscNullsFirst- :: Expression outer commons grp schemas params from ('Null ty)- -> SortExpression outer commons grp schemas params from+ :: Expression grp lat with db params from ('Null ty)+ -- ^ sort by+ -> SortExpression grp lat with db params from AscNullsLast- :: Expression outer commons grp schemas params from ('Null ty)- -> SortExpression outer commons grp schemas params from+ :: Expression grp lat with db params from ('Null ty)+ -- ^ sort by+ -> SortExpression grp lat with db params from DescNullsFirst- :: Expression outer commons grp schemas params from ('Null ty)- -> SortExpression outer commons grp schemas params from+ :: Expression grp lat with db params from ('Null ty)+ -- ^ sort by+ -> SortExpression grp lat with db params from DescNullsLast- :: Expression outer commons grp schemas params from ('Null ty)- -> SortExpression outer commons grp schemas params from-deriving instance Show (SortExpression outer commons grp schemas params from)-instance RenderSQL (SortExpression outer commons grp schemas params from) where+ :: Expression grp lat with db params from ('Null ty)+ -- ^ sort by+ -> SortExpression grp lat with db params from+deriving instance Show (SortExpression grp lat with db params from)+instance RenderSQL (SortExpression grp lat with db params from) where renderSQL = \case Asc expression -> renderSQL expression <+> "ASC" Desc expression -> renderSQL expression <+> "DESC"@@ -66,6 +76,11 @@ <+> "DESC NULLS FIRST" AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST" DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"+instance RenderSQL [SortExpression grp lat with db params from] where+ renderSQL = \case+ [] -> ""+ srts -> " ORDER BY"+ <+> commaSeparated (renderSQL <$> srts) {- | The `orderBy` clause causes the result rows of a `Squeal.PostgreSQL.Query.TableExpression`@@ -78,8 +93,9 @@ You can also control the order in which rows are processed by window functions using `orderBy` within `Squeal.PostgreSQL.Query.Over`. -}-class OrderBy expr where+class OrderBy expr grp | expr -> grp where orderBy- :: [SortExpression outer commons grp schemas params from]- -> expr outer commons grp schemas params from- -> expr outer commons grp schemas params from+ :: [SortExpression grp lat with db params from]+ -- ^ sorts+ -> expr lat with db params from+ -> expr lat with db params from
src/Squeal/PostgreSQL/Expression/Subquery.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Subquery-Description: Subquery expressions+Description: subquery expressions Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Subquery expressions+subquery expressions -} {-# LANGUAGE@@ -16,20 +16,21 @@ #-} module Squeal.PostgreSQL.Expression.Subquery- ( exists+ ( -- * Subquery+ exists , in_ , notIn , subAll , subAny ) where -import Squeal.PostgreSQL.Alias+import Squeal.PostgreSQL.Type.Alias import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Expression.Logic-import Squeal.PostgreSQL.List+import Squeal.PostgreSQL.Type.List import Squeal.PostgreSQL.Query import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -47,8 +48,9 @@ at least one row is returned, not all the way to completion. -} exists- :: Query (Join outer from) commons schemas params row- -> Condition outer commons grp schemas params from+ :: Query (Join lat from) with db params row+ -- ^ subquery+ -> Expression grp lat with db params from (null 'PGbool) exists query = UnsafeExpression $ "EXISTS" <+> parenthesized (renderSQL query) {- |@@ -66,10 +68,10 @@ (TRUE = ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo"))) -} subAll- :: Expression outer commons grp schemas params from ty1 -- ^ expression+ :: Expression grp lat with db params from ty1 -- ^ expression -> Operator ty1 ty2 ('Null 'PGbool) -- ^ operator- -> Query (Join outer from) commons schemas params '[col ::: ty2] -- ^ subquery- -> Condition outer commons grp schemas params from+ -> Query (Join lat from) with db params '[col ::: ty2] -- ^ subquery+ -> Condition grp lat with db params from subAll expr (?) qry = expr ? (UnsafeExpression $ "ALL" <+> parenthesized (renderSQL qry)) @@ -81,13 +83,13 @@ (including the case where the subquery returns no rows). >>> printSQL $ subAny "foo" like (values_ ("foobar" `as` #foo))-(E'foo' LIKE ANY (SELECT * FROM (VALUES (E'foobar')) AS t ("foo")))+((E'foo' :: text) LIKE ANY (SELECT * FROM (VALUES ((E'foobar' :: text))) AS t ("foo"))) -} subAny- :: Expression outer commons grp schemas params from ty1 -- ^ expression+ :: Expression grp lat with db params from ty1 -- ^ expression -> Operator ty1 ty2 ('Null 'PGbool) -- ^ operator- -> Query (Join outer from) commons schemas params '[col ::: ty2] -- ^ subquery- -> Condition outer commons grp schemas params from+ -> Query (Join lat from) with db params '[col ::: ty2] -- ^ subquery+ -> Condition grp lat with db params from subAny expr (?) qry = expr ? (UnsafeExpression $ "ANY" <+> parenthesized (renderSQL qry)) @@ -99,9 +101,9 @@ TRUE IN (TRUE, FALSE, NULL) -} in_- :: Expression outer commons grp schemas params from ty -- ^ expression- -> [Expression outer commons grp schemas params from ty]- -> Condition outer commons grp schemas params from+ :: Expression grp lat with db params from ty -- ^ expression+ -> [Expression grp lat with db params from ty]+ -> Expression grp lat with db params from (null 'PGbool) expr `in_` exprs = UnsafeExpression $ renderSQL expr <+> "IN" <+> parenthesized (commaSeparated (renderSQL <$> exprs)) @@ -113,8 +115,8 @@ TRUE NOT IN (FALSE, NULL) -} notIn- :: Expression outer commons grp schemas params from ty -- ^ expression- -> [Expression outer commons grp schemas params from ty]- -> Condition outer commons grp schemas params from+ :: Expression grp lat with db params from ty -- ^ expression+ -> [Expression grp lat with db params from ty]+ -> Expression grp lat with db params from (null 'PGbool) expr `notIn` exprs = UnsafeExpression $ renderSQL expr <+> "NOT IN" <+> parenthesized (commaSeparated (renderSQL <$> exprs))
src/Squeal/PostgreSQL/Expression/Text.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Text-Description: Text expressions+Description: text functions and operators Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -String functions and operators+text functions and operators -} {-# LANGUAGE@@ -15,7 +15,8 @@ #-} module Squeal.PostgreSQL.Expression.Text- ( lower+ ( -- * Text Function+ lower , upper , charLength , like@@ -23,24 +24,24 @@ ) where import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL -- | >>> printSQL $ lower "ARRRGGG"--- lower(E'ARRRGGG')-lower :: null 'PGtext :--> null 'PGtext+-- lower((E'ARRRGGG' :: text))+lower :: null 'PGtext --> null 'PGtext lower = unsafeFunction "lower" -- | >>> printSQL $ upper "eeee"--- upper(E'eeee')-upper :: null 'PGtext :--> null 'PGtext+-- upper((E'eeee' :: text))+upper :: null 'PGtext --> null 'PGtext upper = unsafeFunction "upper" -- | >>> printSQL $ charLength "four"--- char_length(E'four')-charLength :: null 'PGtext :--> null 'PGint4+-- char_length((E'four' :: text))+charLength :: null 'PGtext --> null 'PGint4 charLength = unsafeFunction "char_length" -- | The `like` expression returns true if the @string@ matches@@ -51,7 +52,7 @@ -- matches any sequence of zero or more characters. -- -- >>> printSQL $ "abc" `like` "a%"--- (E'abc' LIKE E'a%')+-- ((E'abc' :: text) LIKE (E'a%' :: text)) like :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool) like = unsafeBinaryOp "LIKE" @@ -59,6 +60,6 @@ -- match case-insensitive according to the active locale. -- -- >>> printSQL $ "abc" `ilike` "a%"--- (E'abc' ILIKE E'a%')+-- ((E'abc' :: text) ILIKE (E'a%' :: text)) ilike :: Operator (null 'PGtext) (null 'PGtext) ('Null 'PGbool) ilike = unsafeBinaryOp "ILIKE"
src/Squeal/PostgreSQL/Expression/TextSearch.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.TextSearch-Description: Text search expressions+Description: text search functions and operators Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Text search functions and operators+text search functions and operators -} {-# LANGUAGE@@ -15,11 +15,13 @@ #-} module Squeal.PostgreSQL.Expression.TextSearch- ( (@@)+ ( -- * Text Search Operator+ (@@) , (.&) , (.|) , (.!) , (<->)+ -- * Text Search Function , arrayToTSvector , tsvectorLength , numnode@@ -39,8 +41,8 @@ ) where import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema -- | `Squeal.PostgreSQL.Expression.Type.tsvector` matches tsquery ? (@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ('Null 'PGbool)@@ -55,8 +57,8 @@ (.|) = unsafeBinaryOp "||" -- | negate a `Squeal.PostgreSQL.Expression.Type.tsquery`-(.!) :: null 'PGtsquery :--> null 'PGtsquery-(.!) = unsafeUnaryOpL "!!"+(.!) :: null 'PGtsquery --> null 'PGtsquery+(.!) = unsafeLeftOp "!!" -- | `Squeal.PostgreSQL.Expression.Type.tsquery` followed by -- `Squeal.PostgreSQL.Expression.Type.tsquery`@@ -66,51 +68,50 @@ -- | convert array of lexemes to `Squeal.PostgreSQL.Expression.Type.tsvector` arrayToTSvector :: null ('PGvararray ('NotNull 'PGtext))- :--> null 'PGtsvector+ --> null 'PGtsvector arrayToTSvector = unsafeFunction "array_to_tsvector" -- | number of lexemes in `Squeal.PostgreSQL.Expression.Type.tsvector`-tsvectorLength :: null 'PGtsvector :--> null 'PGint4+tsvectorLength :: null 'PGtsvector --> null 'PGint4 tsvectorLength = unsafeFunction "length" -- | number of lexemes plus operators in `Squeal.PostgreSQL.Expression.Type.tsquery`-numnode :: null 'PGtsquery :--> null 'PGint4+numnode :: null 'PGtsquery --> null 'PGint4 numnode = unsafeFunction "numnode" -- | produce `Squeal.PostgreSQL.Expression.Type.tsquery` ignoring punctuation-plainToTSquery :: null 'PGtext :--> null 'PGtsquery+plainToTSquery :: null 'PGtext --> null 'PGtsquery plainToTSquery = unsafeFunction "plainto_tsquery" -- | produce `Squeal.PostgreSQL.Expression.Type.tsquery` that searches for a phrase, -- ignoring punctuation-phraseToTSquery :: null 'PGtext :--> null 'PGtsquery+phraseToTSquery :: null 'PGtext --> null 'PGtsquery phraseToTSquery = unsafeFunction "phraseto_tsquery" -- | produce `Squeal.PostgreSQL.Expression.Type.tsquery` from a web search style query-websearchToTSquery :: null 'PGtext :--> null 'PGtsquery+websearchToTSquery :: null 'PGtext --> null 'PGtsquery websearchToTSquery = unsafeFunction "websearch_to_tsquery" -- | get indexable part of a `Squeal.PostgreSQL.Expression.Type.tsquery`-queryTree :: null 'PGtsquery :--> null 'PGtext+queryTree :: null 'PGtsquery --> null 'PGtext queryTree = unsafeFunction "query_tree" -- | normalize words and convert to `Squeal.PostgreSQL.Expression.Type.tsquery`-toTSquery :: null 'PGtext :--> null 'PGtsquery+toTSquery :: null 'PGtext --> null 'PGtsquery toTSquery = unsafeFunction "to_tsquery" -- | reduce document text to `Squeal.PostgreSQL.Expression.Type.tsvector` toTSvector :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb]- => null ty :--> null 'PGtsvector+ => null ty --> null 'PGtsvector toTSvector = unsafeFunction "to_tsvector" -- | assign weight to each element of `Squeal.PostgreSQL.Expression.Type.tsvector`-setWeight- :: FunctionN '[null 'PGtsvector, null ('PGchar 1)] (null 'PGtsvector)+setWeight :: '[null 'PGtsvector, null ('PGchar 1)] ---> null 'PGtsvector setWeight = unsafeFunctionN "set_weight" -- | remove positions and weights from `Squeal.PostgreSQL.Expression.Type.tsvector`-strip :: null 'PGtsvector :--> null 'PGtsvector+strip :: null 'PGtsvector --> null 'PGtsvector strip = unsafeFunction "strip" -- | @jsonToTSvector (document *: filter)@@@ -123,7 +124,7 @@ -- "boolean" (to include all Boolean values in the string format "true"/"false"), -- "key" (to include all keys) or "all" (to include all above). -- These values can be combined together to include, e.g. all string and numeric values.-jsonToTSvector :: FunctionN '[null 'PGjson, null 'PGjson] (null 'PGtsvector)+jsonToTSvector :: '[null 'PGjson, null 'PGjson] ---> null 'PGtsvector jsonToTSvector = unsafeFunctionN "json_to_tsvector" -- | @jsonbToTSvector (document *: filter)@@@ -136,23 +137,23 @@ -- "boolean" (to include all Boolean values in the string format "true"/"false"), -- "key" (to include all keys) or "all" (to include all above). -- These values can be combined together to include, e.g. all string and numeric values.-jsonbToTSvector :: FunctionN '[null 'PGjsonb, null 'PGjsonb] (null 'PGtsvector)+jsonbToTSvector :: '[null 'PGjsonb, null 'PGjsonb] ---> null 'PGtsvector jsonbToTSvector = unsafeFunctionN "jsonb_to_tsvector" -- | remove given lexeme from `Squeal.PostgreSQL.Expression.Type.tsvector`-tsDelete :: FunctionN+tsDelete :: '[null 'PGtsvector, null ('PGvararray ('NotNull 'PGtext))]- (null 'PGtsvector)+ ---> null 'PGtsvector tsDelete = unsafeFunctionN "ts_delete" -- | select only elements with given weights from `Squeal.PostgreSQL.Expression.Type.tsvector`-tsFilter :: FunctionN+tsFilter :: '[null 'PGtsvector, null ('PGvararray ('NotNull ('PGchar 1)))]- (null 'PGtsvector)+ ---> null 'PGtsvector tsFilter = unsafeFunctionN "ts_filter" -- | display a `Squeal.PostgreSQL.Expression.Type.tsquery` match tsHeadline :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb]- => FunctionN '[null document, null 'PGtsquery] (null 'PGtext)+ => '[null document, null 'PGtsquery] ---> null 'PGtext tsHeadline = unsafeFunctionN "ts_headline"
src/Squeal/PostgreSQL/Expression/Time.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Expression.Time-Description: Date/Time expressions+Description: date/time functions and operators Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Date/Time functions and operators+date/time functions and operators -} {-# LANGUAGE@@ -17,10 +17,13 @@ , OverloadedStrings , PolyKinds , RankNTypes+ , TypeOperators #-} module Squeal.PostgreSQL.Expression.Time- ( TimeOp (..)+ ( -- * Time Operation+ TimeOp (..)+ -- * Time Function , currentDate , currentTime , currentTimestamp@@ -31,10 +34,12 @@ , makeTime , makeTimestamp , makeTimestamptz+ -- * Interval , interval_ , TimeUnit (..) ) where +import Data.Fixed import Data.String import qualified GHC.Generics as GHC@@ -42,7 +47,7 @@ import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -83,34 +88,29 @@ Create date from year, month and day fields >>> printSQL (makeDate (1984 :* 7 *: 3))-make_date(1984, 7, 3)+make_date((1984 :: int4), (7 :: int4), (3 :: int4)) -}-makeDate :: FunctionN- '[ null 'PGint4, null 'PGint4, null 'PGint4 ]- ( null 'PGdate )+makeDate :: '[ null 'PGint4, null 'PGint4, null 'PGint4 ] ---> null 'PGdate makeDate = unsafeFunctionN "make_date" {-| Create time from hour, minute and seconds fields >>> printSQL (makeTime (8 :* 15 *: 23.5))-make_time(8, 15, 23.5)+make_time((8 :: int4), (15 :: int4), (23.5 :: float8)) -}-makeTime :: FunctionN- '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ]- ( null 'PGtime )+makeTime :: '[ null 'PGint4, null 'PGint4, null 'PGfloat8 ] ---> null 'PGtime makeTime = unsafeFunctionN "make_time" {-| Create timestamp from year, month, day, hour, minute and seconds fields >>> printSQL (makeTimestamp (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))-make_timestamp(2013, 7, 15, 8, 15, 23.5)+make_timestamp((2013 :: int4), (7 :: int4), (15 :: int4), (8 :: int4), (15 :: int4), (23.5 :: float8)) -}-makeTimestamp :: FunctionN+makeTimestamp :: '[ null 'PGint4, null 'PGint4, null 'PGint4- , null 'PGint4, null 'PGint4, null 'PGfloat8 ]- ( null 'PGtimestamp )+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ] ---> null 'PGtimestamp makeTimestamp = unsafeFunctionN "make_timestamp" {-|@@ -119,12 +119,11 @@ the current time zone is used >>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5))-make_timestamptz(2013, 7, 15, 8, 15, 23.5)+make_timestamptz((2013 :: int4), (7 :: int4), (15 :: int4), (8 :: int4), (15 :: int4), (23.5 :: float8)) -}-makeTimestamptz :: FunctionN+makeTimestamptz :: '[ null 'PGint4, null 'PGint4, null 'PGint4- , null 'PGint4, null 'PGint4, null 'PGfloat8 ]- ( null 'PGtimestamptz )+ , null 'PGint4, null 'PGint4, null 'PGfloat8 ] ---> null 'PGtimestamptz makeTimestamptz = unsafeFunctionN "make_timestamptz" {-|@@ -133,25 +132,25 @@ class TimeOp time diff | time -> diff where {-| >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365)- (make_date(1984, 7, 3) + 365)+ (make_date((1984 :: int4), (7 :: int4), (3 :: int4)) + (365 :: int4)) -} (!+) :: Operator (null time) (null diff) (null time) (!+) = unsafeBinaryOp "+" {-| >>> printSQL (365 +! makeDate (1984 :* 7 *: 3))- (365 + make_date(1984, 7, 3))+ ((365 :: int4) + make_date((1984 :: int4), (7 :: int4), (3 :: int4))) -} (+!) :: Operator (null diff) (null time) (null time) (+!) = unsafeBinaryOp "+" {-| >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365)- (make_date(1984, 7, 3) - 365)+ (make_date((1984 :: int4), (7 :: int4), (3 :: int4)) - (365 :: int4)) -} (!-) :: Operator (null time) (null diff) (null time) (!-) = unsafeBinaryOp "-" {-| >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate)- (make_date(1984, 7, 3) - CURRENT_DATE)+ (make_date((1984 :: int4), (7 :: int4), (3 :: int4)) - CURRENT_DATE) -} (!-!) :: Operator (null time) (null time) (null diff) (!-!) = unsafeBinaryOp "-"@@ -191,7 +190,7 @@ Millennia -> "millennia" -- | >>> printSQL $ interval_ 7 Days--- (INTERVAL '7.0 days')-interval_ :: Double -> TimeUnit -> Expr (null 'PGinterval)+-- (INTERVAL '7.000 days')+interval_ :: Milli -> TimeUnit -> Expr (null 'PGinterval) interval_ num unit = UnsafeExpression . parenthesized $ "INTERVAL" <+> "'" <> fromString (show num) <+> renderSQL unit <> "'"
src/Squeal/PostgreSQL/Expression/Type.hs view
@@ -1,17 +1,18 @@ {-| Module: Squeal.PostgreSQL.Expression-Description: Type expressions+Description: type expressions Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Type expressions.+type expressions -} {-# LANGUAGE AllowAmbiguousTypes , DataKinds , DeriveGeneric+ , DerivingStrategies , FlexibleContexts , FlexibleInstances , GADTs@@ -23,14 +24,16 @@ , ScopedTypeVariables , TypeApplications , TypeOperators+ , UndecidableInstances #-} module Squeal.PostgreSQL.Expression.Type- ( TypeExpression (..)- , cast+ ( -- * Type Cast+ cast , astype , inferredtype- , PGTyped (..)+ -- * Type Expression+ , TypeExpression (..) , typedef , typetable , typeview@@ -56,9 +59,11 @@ , bytea , timestamp , timestampWithTimeZone+ , timestamptz , date , time , timeWithTimeZone+ , timetz , interval , uuid , inet@@ -68,6 +73,33 @@ , fixarray , tsvector , tsquery+ , oid+ , int4range+ , int8range+ , numrange+ , tsrange+ , tstzrange+ , daterange+ , record+ -- * Column Type+ , ColumnTypeExpression (..)+ , nullable+ , notNullable+ , default_+ , serial2+ , smallserial+ , serial4+ , serial+ , serial8+ , bigserial+ -- * Type Inference+ , PGTyped (..)+ , pgtypeFrom+ , NullTyped (..)+ , nulltypeFrom+ , ColumnTyped (..)+ , columntypeFrom+ , FieldTyped (..) ) where import Control.DeepSeq@@ -79,10 +111,11 @@ import qualified GHC.Generics as GHC import qualified Generics.SOP as SOP -import Squeal.PostgreSQL.Alias+import Squeal.PostgreSQL.Type.Alias import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Type.PG import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -94,24 +127,24 @@ -- | >>> printSQL $ true & cast int4 -- (TRUE :: int4) cast- :: TypeExpression schemas ty1+ :: TypeExpression db ty1 -- ^ type to cast as- -> Expression outer commons grp schemas params from ty0+ -> Expression grp lat with db params from ty0 -- ^ value to convert- -> Expression outer commons grp schemas params from ty1+ -> Expression grp lat with db params from ty1 cast ty x = UnsafeExpression $ parenthesized $ renderSQL x <+> "::" <+> renderSQL ty -- | A safe version of `cast` which just matches a value with its type. -- -- >>> printSQL (1 & astype int)--- (1 :: int)+-- ((1 :: int4) :: int) astype- :: TypeExpression schemas ty+ :: TypeExpression db ty -- ^ type to specify as- -> Expression outer commons grp schemas params from ty+ -> Expression grp lat with db params from ty -- ^ value- -> Expression outer commons grp schemas params from ty+ -> Expression grp lat with db params from ty astype = cast -- | `inferredtype` will add a type annotation to an `Expression`@@ -120,10 +153,11 @@ -- >>> printSQL (inferredtype true) -- (TRUE :: bool) inferredtype- :: PGTyped schemas ty- => Expression outer common grp schemas params from ty- -> Expression outer common grp schemas params from ty-inferredtype = astype pgtype+ :: NullTyped db ty+ => Expression lat common grp db params from ty+ -- ^ value+ -> Expression lat common grp db params from ty+inferredtype = astype nulltype {----------------------------------------- type expressions@@ -131,127 +165,133 @@ -- | `TypeExpression`s are used in `cast`s and -- `Squeal.PostgreSQL.Definition.createTable` commands.-newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType)+newtype TypeExpression (db :: SchemasType) (ty :: NullType) = UnsafeTypeExpression { renderTypeExpression :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL (TypeExpression schemas ty) where+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (TypeExpression db ty) where renderSQL = renderTypeExpression -- | The enum or composite type in a `Typedef` can be expressed by its alias. typedef- :: (Has sch schemas schema, Has td schema ('Typedef ty))+ :: (Has sch db schema, Has td schema ('Typedef ty)) => QualifiedAlias sch td- -> TypeExpression schemas (null ty)+ -- ^ type alias+ -> TypeExpression db (null ty) typedef = UnsafeTypeExpression . renderSQL -- | The composite type corresponding to a `Table` definition can be expressed -- by its alias. typetable- :: (Has sch schemas schema, Has tab schema ('Table table))+ :: (Has sch db schema, Has tab schema ('Table table)) => QualifiedAlias sch tab- -> TypeExpression schemas (null ('PGcomposite (TableToRow table)))+ -- ^ table alias+ -> TypeExpression db (null ('PGcomposite (TableToRow table))) typetable = UnsafeTypeExpression . renderSQL -- | The composite type corresponding to a `View` definition can be expressed -- by its alias. typeview- :: (Has sch schemas schema, Has vw schema ('View view))+ :: (Has sch db schema, Has vw schema ('View view)) => QualifiedAlias sch vw- -> TypeExpression schemas (null ('PGcomposite view))+ -- ^ view alias+ -> TypeExpression db (null ('PGcomposite view)) typeview = UnsafeTypeExpression . renderSQL -- | logical Boolean (true/false)-bool :: TypeExpression schemas (null 'PGbool)+bool :: TypeExpression db (null 'PGbool) bool = UnsafeTypeExpression "bool" -- | signed two-byte integer-int2, smallint :: TypeExpression schemas (null 'PGint2)+int2, smallint :: TypeExpression db (null 'PGint2) int2 = UnsafeTypeExpression "int2" smallint = UnsafeTypeExpression "smallint" -- | signed four-byte integer-int4, int, integer :: TypeExpression schemas (null 'PGint4)+int4, int, integer :: TypeExpression db (null 'PGint4) int4 = UnsafeTypeExpression "int4" int = UnsafeTypeExpression "int" integer = UnsafeTypeExpression "integer" -- | signed eight-byte integer-int8, bigint :: TypeExpression schemas (null 'PGint8)+int8, bigint :: TypeExpression db (null 'PGint8) int8 = UnsafeTypeExpression "int8" bigint = UnsafeTypeExpression "bigint" -- | arbitrary precision numeric type-numeric :: TypeExpression schemas (null 'PGnumeric)+numeric :: TypeExpression db (null 'PGnumeric) numeric = UnsafeTypeExpression "numeric" -- | single precision floating-point number (4 bytes)-float4, real :: TypeExpression schemas (null 'PGfloat4)+float4, real :: TypeExpression db (null 'PGfloat4) float4 = UnsafeTypeExpression "float4" real = UnsafeTypeExpression "real" -- | double precision floating-point number (8 bytes)-float8, doublePrecision :: TypeExpression schemas (null 'PGfloat8)+float8, doublePrecision :: TypeExpression db (null 'PGfloat8) float8 = UnsafeTypeExpression "float8" doublePrecision = UnsafeTypeExpression "double precision" -- | currency amount money :: TypeExpression schema (null 'PGmoney) money = UnsafeTypeExpression "money" -- | variable-length character string-text :: TypeExpression schemas (null 'PGtext)+text :: TypeExpression db (null 'PGtext) text = UnsafeTypeExpression "text" -- | fixed-length character string char, character- :: forall n schemas null. (KnownNat n, 1 <= n)- => TypeExpression schemas (null ('PGchar n))+ :: forall n db null. (KnownNat n, 1 <= n)+ => TypeExpression db (null ('PGchar n)) char = UnsafeTypeExpression $ "char(" <> renderNat @n <> ")" character = UnsafeTypeExpression $ "character(" <> renderNat @n <> ")" -- | variable-length character string varchar, characterVarying- :: forall n schemas null. (KnownNat n, 1 <= n)- => TypeExpression schemas (null ('PGvarchar n))+ :: forall n db null. (KnownNat n, 1 <= n)+ => TypeExpression db (null ('PGvarchar n)) varchar = UnsafeTypeExpression $ "varchar(" <> renderNat @n <> ")" characterVarying = UnsafeTypeExpression $ "character varying(" <> renderNat @n <> ")" -- | binary data ("byte array")-bytea :: TypeExpression schemas (null 'PGbytea)+bytea :: TypeExpression db (null 'PGbytea) bytea = UnsafeTypeExpression "bytea" -- | date and time (no time zone)-timestamp :: TypeExpression schemas (null 'PGtimestamp)+timestamp :: TypeExpression db (null 'PGtimestamp) timestamp = UnsafeTypeExpression "timestamp" -- | date and time, including time zone-timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz)+timestampWithTimeZone, timestamptz :: TypeExpression db (null 'PGtimestamptz) timestampWithTimeZone = UnsafeTypeExpression "timestamp with time zone"+timestamptz = UnsafeTypeExpression "timestamptz" -- | calendar date (year, month, day)-date :: TypeExpression schemas (null 'PGdate)+date :: TypeExpression db (null 'PGdate) date = UnsafeTypeExpression "date" -- | time of day (no time zone)-time :: TypeExpression schemas (null 'PGtime)+time :: TypeExpression db (null 'PGtime) time = UnsafeTypeExpression "time" -- | time of day, including time zone-timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz)+timeWithTimeZone, timetz :: TypeExpression db (null 'PGtimetz) timeWithTimeZone = UnsafeTypeExpression "time with time zone"+timetz = UnsafeTypeExpression "timetz" -- | time span-interval :: TypeExpression schemas (null 'PGinterval)+interval :: TypeExpression db (null 'PGinterval) interval = UnsafeTypeExpression "interval" -- | universally unique identifier-uuid :: TypeExpression schemas (null 'PGuuid)+uuid :: TypeExpression db (null 'PGuuid) uuid = UnsafeTypeExpression "uuid" -- | IPv4 or IPv6 host address-inet :: TypeExpression schemas (null 'PGinet)+inet :: TypeExpression db (null 'PGinet) inet = UnsafeTypeExpression "inet" -- | textual JSON data-json :: TypeExpression schemas (null 'PGjson)+json :: TypeExpression db (null 'PGjson) json = UnsafeTypeExpression "json" -- | binary JSON data, decomposed-jsonb :: TypeExpression schemas (null 'PGjsonb)+jsonb :: TypeExpression db (null 'PGjsonb) jsonb = UnsafeTypeExpression "jsonb" -- | variable length array vararray- :: TypeExpression schemas pg- -> TypeExpression schemas (null ('PGvararray pg))+ :: TypeExpression db pg+ -> TypeExpression db (null ('PGvararray pg)) vararray ty = UnsafeTypeExpression $ renderSQL ty <> "[]" -- | fixed length array -- -- >>> renderSQL (fixarray @'[2] json) -- "json[2]" fixarray- :: forall dims schemas null pg. SOP.All KnownNat dims- => TypeExpression schemas pg- -> TypeExpression schemas (null ('PGfixarray dims pg))+ :: forall dims db null pg. SOP.All KnownNat dims+ => TypeExpression db pg+ -> TypeExpression db (null ('PGfixarray dims pg)) fixarray ty = UnsafeTypeExpression $ renderSQL ty <> renderDims @dims where@@ -262,46 +302,204 @@ . ByteString.intercalate "][" . SOP.hcollapse $ SOP.hcmap (SOP.Proxy @KnownNat)- (K . fromString . show . natVal)+ (SOP.K . fromString . show . natVal) (SOP.hpure SOP.Proxy :: SOP.NP SOP.Proxy ns) -- | text search query-tsvector :: TypeExpression schemas (null 'PGtsvector)+tsvector :: TypeExpression db (null 'PGtsvector) tsvector = UnsafeTypeExpression "tsvector" -- | text search document-tsquery :: TypeExpression schemas (null 'PGtsquery)+tsquery :: TypeExpression db (null 'PGtsquery) tsquery = UnsafeTypeExpression "tsquery"+-- | Object identifiers (OIDs) are used internally by PostgreSQL+-- as primary keys for various system tables.+oid :: TypeExpression db (null 'PGoid)+oid = UnsafeTypeExpression "oid"+-- | Range of integer+int4range :: TypeExpression db (null ('PGrange 'PGint4))+int4range = UnsafeTypeExpression "int4range"+-- | Range of bigint+int8range :: TypeExpression db (null ('PGrange 'PGint8))+int8range = UnsafeTypeExpression "int8range"+-- | Range of numeric+numrange :: TypeExpression db (null ('PGrange 'PGnumeric))+numrange = UnsafeTypeExpression "numrange"+-- | Range of timestamp without time zone+tsrange :: TypeExpression db (null ('PGrange 'PGtimestamp))+tsrange = UnsafeTypeExpression "tsrange"+-- | Range of timestamp with time zone+tstzrange :: TypeExpression db (null ('PGrange 'PGtimestamptz))+tstzrange = UnsafeTypeExpression "tstzrange"+-- | Range of date+daterange :: TypeExpression db (null ('PGrange 'PGdate))+daterange = UnsafeTypeExpression "daterange"+-- | Anonymous composite record+record :: TypeExpression db (null ('PGcomposite record))+record = UnsafeTypeExpression "record" -- | `pgtype` is a demoted version of a `PGType`-class PGTyped schemas (ty :: NullityType) where- pgtype :: TypeExpression schemas ty-instance PGTyped schemas (null 'PGbool) where pgtype = bool-instance PGTyped schemas (null 'PGint2) where pgtype = int2-instance PGTyped schemas (null 'PGint4) where pgtype = int4-instance PGTyped schemas (null 'PGint8) where pgtype = int8-instance PGTyped schemas (null 'PGnumeric) where pgtype = numeric-instance PGTyped schemas (null 'PGfloat4) where pgtype = float4-instance PGTyped schemas (null 'PGfloat8) where pgtype = float8-instance PGTyped schemas (null 'PGmoney) where pgtype = money-instance PGTyped schemas (null 'PGtext) where pgtype = text+class PGTyped db (ty :: PGType) where pgtype :: TypeExpression db (null ty)+instance PGTyped db 'PGbool where pgtype = bool+instance PGTyped db 'PGint2 where pgtype = int2+instance PGTyped db 'PGint4 where pgtype = int4+instance PGTyped db 'PGint8 where pgtype = int8+instance PGTyped db 'PGnumeric where pgtype = numeric+instance PGTyped db 'PGfloat4 where pgtype = float4+instance PGTyped db 'PGfloat8 where pgtype = float8+instance PGTyped db 'PGmoney where pgtype = money+instance PGTyped db 'PGtext where pgtype = text instance (KnownNat n, 1 <= n)- => PGTyped schemas (null ('PGchar n)) where pgtype = char @n+ => PGTyped db ('PGchar n) where pgtype = char @n instance (KnownNat n, 1 <= n)- => PGTyped schemas (null ('PGvarchar n)) where pgtype = varchar @n-instance PGTyped schemas (null 'PGbytea) where pgtype = bytea-instance PGTyped schemas (null 'PGtimestamp) where pgtype = timestamp-instance PGTyped schemas (null 'PGtimestamptz) where pgtype = timestampWithTimeZone-instance PGTyped schemas (null 'PGdate) where pgtype = date-instance PGTyped schemas (null 'PGtime) where pgtype = time-instance PGTyped schemas (null 'PGtimetz) where pgtype = timeWithTimeZone-instance PGTyped schemas (null 'PGinterval) where pgtype = interval-instance PGTyped schemas (null 'PGuuid) where pgtype = uuid-instance PGTyped schemas (null 'PGjson) where pgtype = json-instance PGTyped schemas (null 'PGjsonb) where pgtype = jsonb-instance PGTyped schemas ty- => PGTyped schemas (null ('PGvararray ty)) where- pgtype = vararray (pgtype @schemas @ty)-instance (SOP.All KnownNat dims, PGTyped schemas ty)- => PGTyped schemas (null ('PGfixarray dims ty)) where- pgtype = fixarray @dims (pgtype @schemas @ty)-instance PGTyped schemas (null 'PGtsvector) where pgtype = tsvector-instance PGTyped schemas (null 'PGtsquery) where pgtype = tsquery+ => PGTyped db ('PGvarchar n) where pgtype = varchar @n+instance PGTyped db 'PGbytea where pgtype = bytea+instance PGTyped db 'PGtimestamp where pgtype = timestamp+instance PGTyped db 'PGtimestamptz where pgtype = timestampWithTimeZone+instance PGTyped db 'PGdate where pgtype = date+instance PGTyped db 'PGtime where pgtype = time+instance PGTyped db 'PGtimetz where pgtype = timeWithTimeZone+instance PGTyped db 'PGinterval where pgtype = interval+instance PGTyped db 'PGuuid where pgtype = uuid+instance PGTyped db 'PGjson where pgtype = json+instance PGTyped db 'PGjsonb where pgtype = jsonb+instance PGTyped db pg => PGTyped db ('PGvararray (null pg)) where+ pgtype = vararray (pgtype @db @pg)+instance (SOP.All KnownNat dims, PGTyped db pg)+ => PGTyped db ('PGfixarray dims (null pg)) where+ pgtype = fixarray @dims (pgtype @db @pg)+instance PGTyped db 'PGtsvector where pgtype = tsvector+instance PGTyped db 'PGtsquery where pgtype = tsquery+instance PGTyped db 'PGoid where pgtype = oid+instance PGTyped db ('PGrange 'PGint4) where pgtype = int4range+instance PGTyped db ('PGrange 'PGint8) where pgtype = int8range+instance PGTyped db ('PGrange 'PGnumeric) where pgtype = numrange+instance PGTyped db ('PGrange 'PGtimestamp) where pgtype = tsrange+instance PGTyped db ('PGrange 'PGtimestamptz) where pgtype = tstzrange+instance PGTyped db ('PGrange 'PGdate) where pgtype = daterange+instance+ ( UserType db ('PGcomposite row) ~ '(sch,td)+ , Has sch db schema+ , Has td schema ('Typedef ('PGcomposite row))+ ) => PGTyped db ('PGcomposite row) where+ pgtype = typedef (QualifiedAlias @sch @td)+instance+ ( UserType db ('PGenum labels) ~ '(sch,td)+ , Has sch db schema+ , Has td schema ('Typedef ('PGenum labels))+ ) => PGTyped db ('PGenum labels) where+ pgtype = typedef (QualifiedAlias @sch @td)++-- | Specify `TypeExpression` from a Haskell type.+--+-- >>> printSQL $ pgtypeFrom @String+-- text+--+-- >>> printSQL $ pgtypeFrom @Double+-- float8+pgtypeFrom+ :: forall hask db null. PGTyped db (PG hask)+ => TypeExpression db (null (PG hask))+pgtypeFrom = pgtype @db @(PG hask)++-- | Lift `PGTyped` to a field+class FieldTyped db ty where fieldtype :: Aliased (TypeExpression db) ty+instance (KnownSymbol alias, NullTyped db ty)+ => FieldTyped db (alias ::: ty) where+ fieldtype = nulltype `As` Alias++-- | `ColumnTypeExpression`s are used in+-- `Squeal.PostgreSQL.Definition.createTable` commands.+newtype ColumnTypeExpression (db :: SchemasType) (ty :: ColumnType)+ = UnsafeColumnTypeExpression { renderColumnTypeExpression :: ByteString }+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (ColumnTypeExpression db ty) where+ renderSQL = renderColumnTypeExpression++-- | used in `Squeal.PostgreSQL.Definition.createTable`+-- commands as a column constraint to note that+-- @NULL@ may be present in a column+nullable+ :: TypeExpression db (null ty)+ -- ^ type+ -> ColumnTypeExpression db ('NoDef :=> 'Null ty)+nullable ty = UnsafeColumnTypeExpression $ renderSQL ty <+> "NULL"++-- | used in `Squeal.PostgreSQL.Definition.createTable`+-- commands as a column constraint to ensure+-- @NULL@ is not present in a column+notNullable+ :: TypeExpression db (null ty)+ -- ^ type+ -> ColumnTypeExpression db ('NoDef :=> 'NotNull ty)+notNullable ty = UnsafeColumnTypeExpression $ renderSQL ty <+> "NOT NULL"++-- | used in `Squeal.PostgreSQL.Definition.createTable`+-- commands as a column constraint to give a default+default_+ :: Expression 'Ungrouped '[] '[] db '[] '[] ty+ -- ^ default value+ -> ColumnTypeExpression db ('NoDef :=> ty)+ -- ^ column type+ -> ColumnTypeExpression db ('Def :=> ty)+default_ x ty = UnsafeColumnTypeExpression $+ renderSQL ty <+> "DEFAULT" <+> renderExpression x++-- | not a true type, but merely a notational convenience for creating+-- unique identifier columns with type `PGint2`+serial2, smallserial+ :: ColumnTypeExpression db ('Def :=> 'NotNull 'PGint2)+serial2 = UnsafeColumnTypeExpression "serial2"+smallserial = UnsafeColumnTypeExpression "smallserial"+-- | not a true type, but merely a notational convenience for creating+-- unique identifier columns with type `PGint4`+serial4, serial+ :: ColumnTypeExpression db ('Def :=> 'NotNull 'PGint4)+serial4 = UnsafeColumnTypeExpression "serial4"+serial = UnsafeColumnTypeExpression "serial"+-- | not a true type, but merely a notational convenience for creating+-- unique identifier columns with type `PGint8`+serial8, bigserial+ :: ColumnTypeExpression db ('Def :=> 'NotNull 'PGint8)+serial8 = UnsafeColumnTypeExpression "serial8"+bigserial = UnsafeColumnTypeExpression "bigserial"++-- | Like @PGTyped@ but also accounts for null.+class NullTyped db (ty :: NullType) where+ nulltype :: TypeExpression db ty++instance PGTyped db ty => NullTyped db (null ty) where+ nulltype = pgtype @db @ty++-- | Specify null `TypeExpression` from a Haskell type.+--+-- >>> printSQL $ nulltypeFrom @(Maybe String)+-- text+--+-- >>> printSQL $ nulltypeFrom @Double+-- float8+nulltypeFrom+ :: forall hask db. NullTyped db (NullPG hask)+ => TypeExpression db (NullPG hask)+nulltypeFrom = nulltype @db @(NullPG hask)++-- | Like @PGTyped@ but also accounts for null.+class ColumnTyped db (column :: ColumnType) where+ columntype :: ColumnTypeExpression db column+instance NullTyped db ('Null ty)+ => ColumnTyped db ('NoDef :=> 'Null ty) where+ columntype = nullable (nulltype @db @('Null ty))+instance NullTyped db ('NotNull ty)+ => ColumnTyped db ('NoDef :=> 'NotNull ty) where+ columntype = notNullable (nulltype @db @('NotNull ty))++-- | Specify `ColumnTypeExpression` from a Haskell type.+--+-- >>> printSQL $ columntypeFrom @(Maybe String)+-- text NULL+--+-- >>> printSQL $ columntypeFrom @Double+-- float8 NOT NULL+columntypeFrom+ :: forall hask db. (ColumnTyped db ('NoDef :=> NullPG hask))+ => ColumnTypeExpression db ('NoDef :=> NullPG hask)+columntypeFrom = columntype @db @('NoDef :=> NullPG hask)
src/Squeal/PostgreSQL/Expression/Window.hs view
@@ -1,30 +1,44 @@ {-| Module: Squeal.PostgreSQL.Expression.Window-Description: Window functions+Description: window functions, arguments and definitions Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Window functions and definitions+window functions, arguments and definitions -} {-# LANGUAGE DataKinds , DeriveGeneric+ , DerivingStrategies , FlexibleContexts , FlexibleInstances , GADTs , GeneralizedNewtypeDeriving+ , KindSignatures , LambdaCase , MultiParamTypeClasses , OverloadedStrings+ , PatternSynonyms , RankNTypes- , KindSignatures+ , TypeOperators #-} module Squeal.PostgreSQL.Expression.Window- ( -- * functions- partitionBy+ ( -- * Window Definition+ WindowDefinition (..)+ , partitionBy+ -- * Window Function+ -- ** Types+ , WindowFunction (..)+ , WindowArg (..)+ , pattern Window+ , pattern Windows+ , WinFun0+ , type (-#->)+ , type (--#->)+ -- ** Functions , rank , rowNumber , denseRank@@ -38,91 +52,79 @@ , nthValue , unsafeWindowFunction1 , unsafeWindowFunctionN- -- * types- , WindowFunction (..)- , WindowDefinition (..)- , WinFun0- , WinFun1- , WinFunN ) where import Control.DeepSeq-import Data.ByteString+import Data.ByteString (ByteString) import qualified GHC.Generics as GHC import qualified Generics.SOP as SOP -import Squeal.PostgreSQL.Alias+import Squeal.PostgreSQL.Type.Alias import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Expression.Aggregate+import Squeal.PostgreSQL.Expression.Logic import Squeal.PostgreSQL.Expression.Sort-import Squeal.PostgreSQL.List+import Squeal.PostgreSQL.Type.List import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -instance Aggregate- (Expression outer commons grp schemas params from)- (NP (Expression outer commons grp schemas params from))- (WindowFunction outer commons grp schemas params from) where- countStar = UnsafeWindowFunction "count(*)"- count = unsafeWindowFunction1 "count"- sum_ = unsafeWindowFunction1 "sum"- arrayAgg = unsafeWindowFunction1 "array_agg"- jsonAgg = unsafeWindowFunction1 "json_agg"- jsonbAgg = unsafeWindowFunction1 "jsonb_agg"- bitAnd = unsafeWindowFunction1 "bit_and"- bitOr = unsafeWindowFunction1 "bit_or"- boolAnd = unsafeWindowFunction1 "bool_and"- boolOr = unsafeWindowFunction1 "bool_or"- every = unsafeWindowFunction1 "every"- max_ = unsafeWindowFunction1 "max"- min_ = unsafeWindowFunction1 "min"- avg = unsafeWindowFunction1 "avg"- corr = unsafeWindowFunctionN "corr"- covarPop = unsafeWindowFunctionN "covar_pop"- covarSamp = unsafeWindowFunctionN "covar_samp"- regrAvgX = unsafeWindowFunctionN "regr_avgx"- regrAvgY = unsafeWindowFunctionN "regr_avgy"- regrCount = unsafeWindowFunctionN "regr_count"- regrIntercept = unsafeWindowFunctionN "regr_intercept"- regrR2 = unsafeWindowFunctionN "regr_r2"- regrSlope = unsafeWindowFunctionN "regr_slope"- regrSxx = unsafeWindowFunctionN "regr_sxx"- regrSxy = unsafeWindowFunctionN "regr_sxy"- regrSyy = unsafeWindowFunctionN "regr_syy"- stddev = unsafeWindowFunction1 "stddev"- stddevPop = unsafeWindowFunction1 "stddev_pop"- stddevSamp = unsafeWindowFunction1 "stddev_samp"- variance = unsafeWindowFunction1 "variance"- varPop = unsafeWindowFunction1 "var_pop"- varSamp = unsafeWindowFunction1 "var_samp"+instance Aggregate (WindowArg grp) (WindowFunction grp) where+ countStar = UnsafeWindowFunction "count(*)"+ count = unsafeWindowFunction1 "count"+ sum_ = unsafeWindowFunction1 "sum"+ arrayAgg = unsafeWindowFunction1 "array_agg"+ jsonAgg = unsafeWindowFunction1 "json_agg"+ jsonbAgg = unsafeWindowFunction1 "jsonb_agg"+ bitAnd = unsafeWindowFunction1 "bit_and"+ bitOr = unsafeWindowFunction1 "bit_or"+ boolAnd = unsafeWindowFunction1 "bool_and"+ boolOr = unsafeWindowFunction1 "bool_or"+ every = unsafeWindowFunction1 "every"+ max_ = unsafeWindowFunction1 "max"+ min_ = unsafeWindowFunction1 "min"+ avg = unsafeWindowFunction1 "avg"+ corr = unsafeWindowFunctionN "corr"+ covarPop = unsafeWindowFunctionN "covar_pop"+ covarSamp = unsafeWindowFunctionN "covar_samp"+ regrAvgX = unsafeWindowFunctionN "regr_avgx"+ regrAvgY = unsafeWindowFunctionN "regr_avgy"+ regrCount = unsafeWindowFunctionN "regr_count"+ regrIntercept = unsafeWindowFunctionN "regr_intercept"+ regrR2 = unsafeWindowFunctionN "regr_r2"+ regrSlope = unsafeWindowFunctionN "regr_slope"+ regrSxx = unsafeWindowFunctionN "regr_sxx"+ regrSxy = unsafeWindowFunctionN "regr_sxy"+ regrSyy = unsafeWindowFunctionN "regr_syy"+ stddev = unsafeWindowFunction1 "stddev"+ stddevPop = unsafeWindowFunction1 "stddev_pop"+ stddevSamp = unsafeWindowFunction1 "stddev_samp"+ variance = unsafeWindowFunction1 "variance"+ varPop = unsafeWindowFunction1 "var_pop"+ varSamp = unsafeWindowFunction1 "var_samp" -- | A `WindowDefinition` is a set of table rows that are somehow related -- to the current row-data WindowDefinition outer commons grp schemas params from where+data WindowDefinition grp lat with db params from where WindowDefinition :: SOP.SListI bys- => NP (Expression outer commons grp schemas params from) bys+ => NP (Expression grp lat with db params from) bys -- ^ `partitionBy` clause- -> [SortExpression outer commons grp schemas params from]+ -> [SortExpression grp lat with db params from] -- ^ `Squeal.PostgreSQL.Expression.Sort.orderBy` clause- -> WindowDefinition outer commons grp schemas params from+ -> WindowDefinition grp lat with db params from -instance OrderBy WindowDefinition where+instance OrderBy (WindowDefinition grp) grp where orderBy sortsR (WindowDefinition parts sortsL) = WindowDefinition parts (sortsL ++ sortsR) -instance RenderSQL (WindowDefinition outer commons schemas from grp params) where+instance RenderSQL (WindowDefinition lat with db from grp params) where renderSQL (WindowDefinition part ord) =- renderPartitionByClause part <> renderOrderByClause ord+ renderPartitionByClause part <> renderSQL ord where renderPartitionByClause = \case Nil -> "" parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts- renderOrderByClause = \case- [] -> ""- srts -> " ORDER" <+> "BY"- <+> commaSeparated (renderSQL <$> srts) {- | The `partitionBy` clause within `Squeal.PostgreSQL.Query.Over` divides the rows into groups,@@ -132,8 +134,8 @@ -} partitionBy :: SOP.SListI bys- => NP (Expression outer commons grp schemas params from) bys -- ^ partitions- -> WindowDefinition outer commons grp schemas params from+ => NP (Expression grp lat with db params from) bys -- ^ partitions+ -> WindowDefinition grp lat with db params from partitionBy bys = WindowDefinition bys [] {- |@@ -147,57 +149,99 @@ just the current row of the query result. -} newtype WindowFunction- (outer :: FromType)- (commons :: FromType) (grp :: Grouping)- (schemas :: SchemasType)- (params :: [NullityType])+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType]) (from :: FromType)- (ty :: NullityType)+ (ty :: NullType) = UnsafeWindowFunction { renderWindowFunction :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData) -instance RenderSQL (WindowFunction outer commons grp schemas params from ty) where+{- |+`WindowArg`s are used for the input of `WindowFunction`s.+-}+data WindowArg+ (grp :: Grouping)+ (args :: [NullType])+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType])+ (from :: FromType)+ = WindowArg+ { windowArgs :: NP (Expression grp lat with db params from) args+ , windowFilter :: [Condition grp lat with db params from]+ } deriving stock (GHC.Generic)++instance SOP.SListI args+ => RenderSQL (WindowArg grp args lat with db params from) where+ renderSQL (WindowArg args filters) =+ parenthesized (renderCommaSeparated renderSQL args)+ & renderFilters filters+ where+ renderFilter wh = "FILTER" <+> parenthesized ("WHERE" <+> wh)+ renderFilters = \case+ [] -> id+ wh:whs -> (<+> renderFilter (renderSQL (foldr (.&&) wh whs)))++instance FilterWhere (WindowArg grp) grp where+ filterWhere wh (WindowArg args filters) = WindowArg args (wh : filters)++-- | `Window` invokes a `WindowFunction` on a single argument.+pattern Window+ :: Expression grp lat with db params from arg+ -> WindowArg grp '[arg] lat with db params from+pattern Window x = Windows (x :* Nil)++-- | `Windows` invokes a `WindowFunction` on multiple argument.+pattern Windows+ :: NP (Expression grp lat with db params from) args+ -> WindowArg grp args lat with db params from+pattern Windows xs = WindowArg xs []++instance RenderSQL (WindowFunction grp lat with db params from ty) where renderSQL = renderWindowFunction {- | A @RankNType@ for window functions with no arguments. -} type WinFun0 x- = forall outer commons grp schemas params from- . WindowFunction outer commons grp schemas params from x+ = forall grp lat with db params from+ . WindowFunction grp lat with db params from x -- ^ cannot reference aliases {- | A @RankNType@ for window functions with 1 argument. -}-type WinFun1 x y- = forall outer commons grp schemas params from- . Expression outer commons grp schemas params from x+type (-#->) x y+ = forall grp lat with db params from+ . WindowArg grp '[x] lat with db params from -- ^ input- -> WindowFunction outer commons grp schemas params from y+ -> WindowFunction grp lat with db params from y -- ^ output {- | A @RankNType@ for window functions with a fixed-length list of heterogeneous arguments. Use the `*:` operator to end your argument lists. -}-type WinFunN xs y- = forall outer commons grp schemas params from- . NP (Expression outer commons grp schemas params from) xs+type (--#->) xs y+ = forall grp lat with db params from+ . WindowArg grp xs lat with db params from -- ^ inputs- -> WindowFunction outer commons grp schemas params from y+ -> WindowFunction grp lat with db params from y -- ^ output -- | escape hatch for defining window functions-unsafeWindowFunction1 :: ByteString -> WinFun1 x y+unsafeWindowFunction1 :: ByteString -> x -#-> y unsafeWindowFunction1 fun x- = UnsafeWindowFunction $ fun <> parenthesized (renderSQL x)+ = UnsafeWindowFunction $ fun <> renderSQL x -- | escape hatch for defining multi-argument window functions-unsafeWindowFunctionN :: SOP.SListI xs => ByteString -> WinFunN xs y-unsafeWindowFunctionN fun xs = UnsafeWindowFunction $ fun <>- parenthesized (renderCommaSeparated renderSQL xs)+unsafeWindowFunctionN :: SOP.SListI xs => ByteString -> xs --#-> y+unsafeWindowFunctionN fun xs = UnsafeWindowFunction $ fun <> renderSQL xs {- | rank of the current row with gaps; same as `rowNumber` of its first peer @@ -243,10 +287,10 @@ {- | integer ranging from 1 to the argument value, dividing the partition as equally as possible ->>> printSQL $ ntile 5-ntile(5)+>>> printSQL $ ntile (Window 5)+ntile((5 :: int4)) -}-ntile :: WinFun1 ('NotNull 'PGint4) ('NotNull 'PGint4)+ntile :: 'NotNull 'PGint4 -#-> 'NotNull 'PGint4 ntile = unsafeWindowFunction1 "ntile" {- | returns value evaluated at the row that is offset rows before the current@@ -254,7 +298,7 @@ (which must be of the same type as value). Both offset and default are evaluated with respect to the current row. -}-lag :: WinFunN '[ty, 'NotNull 'PGint4, ty] ty+lag :: '[ty, 'NotNull 'PGint4, ty] --#-> ty lag = unsafeWindowFunctionN "lag" {- | returns value evaluated at the row that is offset rows after the current@@ -262,23 +306,23 @@ (which must be of the same type as value). Both offset and default are evaluated with respect to the current row. -}-lead :: WinFunN '[ty, 'NotNull 'PGint4, ty] ty+lead :: '[ty, 'NotNull 'PGint4, ty] --#-> ty lead = unsafeWindowFunctionN "lead" {- | returns value evaluated at the row that is the first row of the window frame -}-firstValue :: WinFun1 ty ty+firstValue :: ty -#-> ty firstValue = unsafeWindowFunction1 "first_value" {- | returns value evaluated at the row that is the last row of the window frame -}-lastValue :: WinFun1 ty ty+lastValue :: ty -#-> ty lastValue = unsafeWindowFunction1 "last_value" {- | returns value evaluated at the row that is the nth row of the window frame (counting from 1); null if no such row -}-nthValue :: WinFunN '[null ty, 'NotNull 'PGint4] ('Null ty)+nthValue :: '[null ty, 'NotNull 'PGint4] --#-> 'Null ty nthValue = unsafeWindowFunctionN "nth_value"
− src/Squeal/PostgreSQL/List.hs
@@ -1,141 +0,0 @@-{-|-Module: Squeal.PostgreSQL.List-Description: List related types and functions-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--Haskell singly-linked lists are very powerful. This module-provides functionality for type-level lists, heterogeneous-lists and type aligned lists.--}--{-# LANGUAGE- DataKinds- , FlexibleContexts- , GADTs- , LambdaCase- , MultiParamTypeClasses- , OverloadedStrings- , PolyKinds- , QuantifiedConstraints- , RankNTypes- , ScopedTypeVariables- , TypeApplications- , TypeFamilies- , TypeOperators- , UndecidableInstances-#-}--module Squeal.PostgreSQL.List- ( SOP.NP (..)- , (*:)- , Join- , disjoin- , Additional (..)- , AlignedList (..)- , single- , extractList- , mapAligned- , Elem- , In- , Length- ) where--import Control.Category-import Data.Function ((&))-import Data.Kind-import Data.Type.Bool-import GHC.TypeLits--import Generics.SOP as SOP--import Squeal.PostgreSQL.Render---- | `Join` is simply promoted `++` and is used in @JOIN@s in--- `Squeal.PostgreSQL.Query.FromClause`s.-type family Join xs ys where- Join '[] ys = ys- Join (x ': xs) ys = x ': Join xs ys---- | `disjoin` is a utility function for splitting an `NP` list into pieces.-disjoin- :: forall xs ys expr. SListI xs- => NP expr (Join xs ys)- -> (NP expr xs, NP expr ys)-disjoin = case sList @xs of- SNil -> \ys -> (Nil, ys)- SCons -> \(x :* xsys) ->- case disjoin xsys of (xs,ys) -> (x :* xs, ys)---- | The `Additional` class is for appending--- type-level list parameterized constructors such as `NP`,--- `Squeal.PostgreSQL.Query.Selection`, and `Squeal.PostgreSQL.Query.FromClause`.-class Additional expr where- also :: expr ys -> expr xs -> expr (Join xs ys)-instance Additional (NP expr) where- also ys = \case- Nil -> ys- x :* xs -> x :* (xs & also ys)---- | An `AlignedList` is a type-aligned list or free category.-data AlignedList p x0 x1 where- Done :: AlignedList p x x- (:>>) :: p x0 x1 -> AlignedList p x1 x2 -> AlignedList p x0 x2-infixr 7 :>>-instance Category (AlignedList p) where- id = Done- (.) list = \case- Done -> list- step :>> steps -> step :>> (steps >>> list)-instance (forall t0 t1. RenderSQL (p t0 t1))- => RenderSQL (AlignedList p x0 x1) where- renderSQL = \case- Done -> ""- step :>> Done -> renderSQL step- step :>> steps -> renderSQL step <> ", " <> renderSQL steps---- | `extractList` turns an `AlignedList` into a standard list.-extractList :: (forall a0 a1. p a0 a1 -> b) -> AlignedList p x0 x1 -> [b]-extractList f = \case- Done -> []- step :>> steps -> (f step):extractList f steps---- | `mapAligned` applies a function to each element of an `AlignedList`.-mapAligned- :: (forall z0 z1. p z0 z1 -> q z0 z1)- -> AlignedList p x0 x1- -> AlignedList q x0 x1-mapAligned f = \case- Done -> Done- x :>> xs -> f x :>> mapAligned f xs---- | A `single` step.-single :: p x0 x1 -> AlignedList p x0 x1-single step = step :>> Done---- | A useful operator for ending an `NP` list of length at least 2 without `Nil`.-(*:) :: f x -> f y -> NP f '[x,y]-x *: y = x :* y :* Nil-infixl 9 *:---- | @Elem@ is a promoted `Data.List.elem`.-type family Elem x xs where- Elem x '[] = 'False- Elem x (x ': xs) = 'True- Elem x (_ ': xs) = Elem x xs---- | @In x xs@ is a constraint that proves that @x@ is in @xs@.-type family In x xs :: Constraint where- In x xs = If (Elem x xs) (() :: Constraint)- (TypeError ('ShowType x ':<>: 'Text "is not in " ':<>: 'ShowType xs))--{- | Calculate the `Length` of a type level list-->>> :kind! Length '[Char,String,Bool,Double]-Length '[Char,String,Bool,Double] :: Nat-= 4--}-type family Length (xs :: [k]) :: Nat where- Length (x : xs) = 1 + Length xs- Length '[] = 0
src/Squeal/PostgreSQL/Manipulation.hs view
@@ -1,15 +1,16 @@ {-| Module: Squeal.PostgreSQL.Manipulation-Description: Squeal data manipulation language-Copyright: (c) Eitan Chatav, 2017+Description: data manipulation language+Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Squeal data manipulation language.+data manipulation language -} {-# LANGUAGE DeriveGeneric+ , DerivingStrategies , FlexibleContexts , FlexibleInstances , GADTs@@ -33,42 +34,27 @@ Manipulation_ , Manipulation (..) , queryStatement- -- * Insert- , insertInto- , insertInto_- -- * Update- , update- , update_- -- * Delete- , deleteFrom- , deleteFrom_- -- * Clauses- , Optional (..)- , QueryClause (..)- , pattern Values_ , ReturningClause (..) , pattern Returning_- , ConflictClause (..)- , ConflictTarget (..)- , ConflictAction (..)- , UsingClause (..) ) where import Control.DeepSeq import Data.ByteString hiding (foldr) import Data.Kind (Type)+import Data.Quiver.Functor import qualified Generics.SOP as SOP import qualified GHC.Generics as GHC -import Squeal.PostgreSQL.Alias+import Squeal.PostgreSQL.Type.Alias import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Expression.Logic-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.PG+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.PG import Squeal.PostgreSQL.Render import Squeal.PostgreSQL.Query-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Query.Select+import Squeal.PostgreSQL.Query.With+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -82,37 +68,45 @@ The general `Manipulation` type is parameterized by -* @commons :: FromType@ - scope for all `common` table expressions,-* @schemas :: SchemasType@ - scope for all `table`s and `view`s,-* @params :: [NullityType]@ - scope for all `Squeal.Expression.Parameter.parameter`s,+* @with :: FromType@ - scope for all `Squeal.PostgreSQL.Query.From.common` table expressions,+* @db :: SchemasType@ - scope for all `Squeal.PostgreSQL.Query.From.table`s and `Squeal.PostgreSQL.Query.From.view`s,+* @params :: [NullType]@ - scope for all `Squeal.Expression.Parameter.parameter`s, * @row :: RowType@ - return type of the `Query`. -} newtype Manipulation- (commons :: FromType)- (schemas :: SchemasType)- (params :: [NullityType])+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType]) (columns :: RowType) = UnsafeManipulation { renderManipulation :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL (Manipulation commons schemas params columns) where+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (Manipulation with db params columns) where renderSQL = renderManipulation instance With Manipulation where with Done manip = manip with ctes manip = UnsafeManipulation $- "WITH" <+> renderSQL ctes <+> renderSQL manip+ "WITH" <+> commaSeparated (qtoList renderSQL ctes) <+> renderSQL manip {- |-The top level `Manipulation_` type is parameterized by a @schemas@ `SchemasType`,-against which the query is type-checked, an input @parameters@ Haskell `Type`,+The top level `Manipulation_` type is parameterized by a @db@ `SchemasType`,+against which the query is type-checked, an input @params@ Haskell `Type`, and an ouput row Haskell `Type`. +`Manipulation_` is a type family which resolves into a `Manipulation`,+so don't be fooled by the input params and output row Haskell `Type`s,+which are converted into appropriate+Postgres @[@`NullType`@]@ params and `RowType` rows.+Use a top-level `Squeal.PostgreSQL.Session.Statement.Statement` to+fix actual Haskell input params and output rows.+ A top-level `Manipulation_` can be run-using `Squeal.PostgreSQL.PQ.manipulateParams`, or if @parameters = ()@-using `Squeal.PostgreSQL.PQ.manipulate`.+using `Squeal.PostgreSQL.Session.manipulateParams`, or if @params = ()@+using `Squeal.PostgreSQL.Session.manipulate`. -Generally, @parameters@ will be a Haskell tuple or record whose entries+Generally, @params@ will be a Haskell tuple or record whose entries may be referenced using positional-`Squeal.PostgreSQL.Expression.Parameter.parameter`s and @row@ will be a+`Squeal.PostgreSQL.Expression.Parameter.param`s and @row@ will be a Haskell record, whose entries will be targeted using overloaded labels. >>> :set -XDeriveAnyClass -XDerivingStrategies@@ -133,21 +127,38 @@ insertInto_ #tab (Values_ (Set 2 `as` #col1 :* Default `as` #col2)) in printSQL manipulation :}-INSERT INTO "tab" ("col1", "col2") VALUES (2, DEFAULT)+INSERT INTO "tab" ("col1", "col2") VALUES ((2 :: int4), DEFAULT) -parameterized insert:+out-of-line parameterized insert: ->>> type Columns = '["col1" ::: 'NoDef :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]+>>> type Columns = '["col1" ::: 'Def :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4] >>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)] >>> :{ let- manipulation :: Manipulation_ (Public Schema) (Int32, Int32) ()+ manipulation :: Manipulation_ (Public Schema) (Only Int32) () manipulation =- insertInto_ #tab (Values_ (Set (param @1) `as` #col1 :* Set (param @2) `as` #col2))+ insertInto_ #tab $ Values_+ (Default `as` #col1 :* Set (param @1) `as` #col2) in printSQL manipulation :}-INSERT INTO "tab" ("col1", "col2") VALUES (($1 :: int4), ($2 :: int4))+INSERT INTO "tab" ("col1", "col2") VALUES (DEFAULT, ($1 :: int4)) +in-line parameterized insert:++>>> type Columns = '["col1" ::: 'Def :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]+>>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]+>>> :{+let+ manipulation+ :: Manipulation_ (Public Schema) () ()+ manipulation =+ insertInto_ #tab $ inlineValues+ (Row {col1 = Default , col2 = 2 :: Int32})+ [Row {col1 = NotDefault (3 :: Int32), col2 = 4 :: Int32}]+in printSQL manipulation+:}+INSERT INTO "tab" ("col1", "col2") VALUES (DEFAULT, (2 :: int4)), ((3 :: int4), (4 :: int4))+ returning insert: >>> :{@@ -158,7 +169,7 @@ OnConflictDoRaise (Returning (#col1 `as` #fromOnly)) in printSQL manipulation :}-INSERT INTO "tab" ("col1", "col2") VALUES (2, 3) RETURNING "col1" AS "fromOnly"+INSERT INTO "tab" ("col1", "col2") VALUES ((2 :: int4), (3 :: int4)) RETURNING "col1" AS "fromOnly" upsert: @@ -176,7 +187,7 @@ (Returning_ Nil) in printSQL manipulation :}-INSERT INTO "customers" ("name", "email") VALUES (E'John Smith', E'john@smith.com') ON CONFLICT ON CONSTRAINT "uq" DO UPDATE SET "email" = ("excluded"."email" || (E'; ' || "customers"."email"))+INSERT INTO "customers" ("name", "email") VALUES ((E'John Smith' :: text), (E'john@smith.com' :: text)) ON CONFLICT ON CONSTRAINT "uq" DO UPDATE SET "email" = ("excluded"."email" || ((E'; ' :: text) || "customers"."email")) query insert: @@ -196,7 +207,7 @@ manipulation = update_ #tab (Set 2 `as` #col1) (#col1 ./= #col2) in printSQL manipulation :}-UPDATE "tab" SET "col1" = 2 WHERE ("col1" <> "col2")+UPDATE "tab" SET "col1" = (2 :: int4) WHERE ("col1" <> "col2") delete: @@ -243,143 +254,31 @@ :} WITH "del" AS (DELETE FROM "products" WHERE ("date" < ($1 :: date)) RETURNING *) INSERT INTO "products_deleted" SELECT * FROM "del" AS "del" -}-type family Manipulation_ (schemas :: SchemasType) (params :: Type) (row :: Type) where- Manipulation_ schemas params row = Manipulation '[] schemas (TuplePG params) (RowPG row)+type family Manipulation_ (db :: SchemasType) (params :: Type) (row :: Type) where+ Manipulation_ db params row = Manipulation '[] db (TuplePG params) (RowPG row) -- | Convert a `Query` into a `Manipulation`. queryStatement- :: Query '[] commons schemas params columns- -> Manipulation commons schemas params columns+ :: Query '[] with db params columns+ -- ^ `Query` to embed as a `Manipulation`+ -> Manipulation with db params columns queryStatement q = UnsafeManipulation $ renderSQL q -{------------------------------------------INSERT statements------------------------------------------}--{- |-When a table is created, it contains no data. The first thing to do-before a database can be of much use is to insert data. Data is-conceptually inserted one row at a time. Of course you can also insert-more than one row, but there is no way to insert less than one row.-Even if you know only some column values, a complete row must be created.--}-insertInto- :: ( Has sch schemas schema- , Has tab schema ('Table table)- , columns ~ TableToColumns table- , row0 ~ TableToRow table- , SOP.SListI columns- , SOP.SListI row1 )- => QualifiedAlias sch tab- -> QueryClause commons schemas params columns- -> ConflictClause tab commons schemas params table- -> ReturningClause commons schemas params '[tab ::: row0] row1- -> Manipulation commons schemas params row1-insertInto tab qry conflict ret = UnsafeManipulation $- "INSERT" <+> "INTO" <+> renderSQL tab- <+> renderSQL qry- <> renderSQL conflict- <> renderSQL ret---- | Like `insertInto` but with `OnConflictDoRaise` and no `ReturningClause`.-insertInto_- :: ( Has sch schemas schema- , Has tab schema ('Table table)- , columns ~ TableToColumns table- , row ~ TableToRow table- , SOP.SListI columns )- => QualifiedAlias sch tab- -> QueryClause commons schemas params columns- -> Manipulation commons schemas params '[]-insertInto_ tab qry =- insertInto tab qry OnConflictDoRaise (Returning_ Nil)---- | A `QueryClause` describes what to `insertInto` a table.-data QueryClause commons schemas params columns where- -- | `Values` describes `NP` lists of `Aliased` `Optional` `Expression`s- -- whose `ColumnsType` must match the tables'.- Values- :: SOP.SListI columns- => NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[]))) columns- -> [NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[]))) columns]- -> QueryClause commons schemas params columns- -- | `Select` describes a subquery that permits use of `Optional` `Expression`s.- Select- :: SOP.SListI columns- => NP (Aliased (Optional (Expression '[] commons grp schemas params from))) columns- -> TableExpression '[] commons grp schemas params from- -> QueryClause commons schemas params columns- -- | `Subquery` describes a subquery whose `RowType` must match the tables'.- Subquery- :: ColumnsToRow columns ~ row- => Query '[] commons schemas params row- -> QueryClause commons schemas params columns--instance RenderSQL (QueryClause commons schemas params columns) where- renderSQL = \case- Values row0 rows ->- parenthesized (renderCommaSeparated renderSQLPart row0)- <+> "VALUES"- <+> commaSeparated- ( parenthesized- . renderCommaSeparated renderValuePart <$> row0 : rows )- Select row0 tab ->- parenthesized (renderCommaSeparatedMaybe renderSQLPartMaybe row0)- <+> "SELECT"- <+> renderCommaSeparatedMaybe renderValuePartMaybe row0- <+> renderSQL tab- Subquery qry -> renderQuery qry- where- renderSQLPartMaybe, renderValuePartMaybe- :: Aliased (Optional (Expression '[] commons grp schemas params from)) column- -> Maybe ByteString- renderSQLPartMaybe = \case- Default `As` _ -> Nothing- Set _ `As` name -> Just $ renderSQL name- renderValuePartMaybe = \case- Default `As` _ -> Nothing- Set value `As` _ -> Just $ renderExpression value- renderSQLPart, renderValuePart- :: Aliased (Optional (Expression '[] commons grp schemas params from)) column- -> ByteString- renderSQLPart (_ `As` name) = renderSQL name- renderValuePart (value `As` _) = renderSQL value---- | `Values_` describes a single `NP` list of `Aliased` `Optional` `Expression`s--- whose `ColumnsType` must match the tables'.-pattern Values_- :: SOP.SListI columns- => NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[]))) columns- -> QueryClause commons schemas params columns-pattern Values_ vals = Values vals []---- | `Optional` is either `Default` or a value, parameterized by an appropriate--- `ColumnConstraint`.-data Optional expr ty where- -- | Use the `Default` value for a column.- Default :: Optional expr ('Def :=> ty)- -- | `Set` a value for a column.- Set :: expr ty -> Optional expr (def :=> ty)--instance (forall x. RenderSQL (expr x)) => RenderSQL (Optional expr ty) where- renderSQL = \case- Default -> "DEFAULT"- Set expr -> renderSQL expr- -- | A `ReturningClause` computes and return value(s) based -- on each row actually inserted, updated or deleted. This is primarily -- useful for obtaining values that were supplied by defaults, such as a -- serial sequence number. However, any expression using the table's columns -- is allowed. Only rows that were successfully inserted or updated or -- deleted will be returned. For example, if a row was locked--- but not updated because an `OnConflict` `DoUpdate` condition was not satisfied,+-- but not updated because an `Squeal.PostgreSQL.Manipulation.Insert.OnConflict`+-- `Squeal.PostgreSQL.Manipulation.Insert.DoUpdate` condition was not satisfied, -- the row will not be returned. `Returning` `Star` will return all columns--- in the row. Use @Returning Nil@ in the common case where no return+-- in the row. Use `Returning` `Nil` in the common case where no return -- values are desired.-newtype ReturningClause commons schemas params from row =- Returning (Selection '[] commons 'Ungrouped schemas params from row)+newtype ReturningClause with db params from row =+ Returning (Selection 'Ungrouped '[] with db params from row) -instance RenderSQL (ReturningClause commons schemas params from row) where+instance RenderSQL (ReturningClause with db params from row) where renderSQL = \case Returning (List Nil) -> "" Returning selection -> " RETURNING" <+> renderSQL selection@@ -387,183 +286,7 @@ -- | `Returning` a `List` pattern Returning_ :: SOP.SListI row- => NP (Aliased (Expression '[] commons 'Ungrouped schemas params from)) row- -> ReturningClause commons schemas params from row+ => NP (Aliased (Expression 'Ungrouped '[] with db params from)) row+ -- ^ row of values+ -> ReturningClause with db params from row pattern Returning_ list = Returning (List list)---- | A `ConflictClause` specifies an action to perform upon a constraint--- violation. `OnConflictDoRaise` will raise an error.--- `OnConflict` `DoNothing` simply avoids inserting a row.--- `OnConflict` `DoUpdate` updates the existing row that conflicts with the row--- proposed for insertion.-data ConflictClause tab commons schemas params table where- OnConflictDoRaise :: ConflictClause tab commons schemas params table- OnConflict- :: ConflictTarget constraints- -> ConflictAction tab commons schemas params columns- -> ConflictClause tab commons schemas params (constraints :=> columns)---- | Render a `ConflictClause`.-instance SOP.SListI (TableToColumns table)- => RenderSQL (ConflictClause tab commons schemas params table) where- renderSQL = \case- OnConflictDoRaise -> ""- OnConflict target action -> " ON CONFLICT"- <+> renderSQL target <+> renderSQL action--{- |-`ConflictAction` specifies an alternative `OnConflict` action.-It can be either `DoNothing`, or a `DoUpdate` clause specifying-the exact details of the `update` action to be performed in case of a conflict.-The `Set` and WHERE `Condition`s in `OnConflict` `DoUpdate` have access to the-existing row using the table's name (or an alias), and to rows proposed-for insertion using the special @#excluded@ table.--}-data ConflictAction tab commons schemas params columns where- -- | `OnConflict` `DoNothing` simply avoids inserting a row as its alternative action.- DoNothing :: ConflictAction tab commons schemas params columns- -- | `OnConflict` `DoUpdate` updates the existing row that conflicts- -- with the row proposed for insertion as its alternative action.- DoUpdate- :: ( row ~ ColumnsToRow columns- , SOP.SListI columns- , columns ~ (col0 ': cols)- , SOP.All (HasIn columns) subcolumns- , AllUnique subcolumns )- => NP (Aliased (Optional (Expression '[] commons 'Ungrouped schemas params '[tab ::: row, "excluded" ::: row]))) subcolumns- -> [Condition '[] commons 'Ungrouped schemas params '[tab ::: row, "excluded" ::: row]]- -- ^ WHERE `Condition`s- -> ConflictAction tab commons schemas params columns--instance RenderSQL (ConflictAction tab commons schemas params columns) where- renderSQL = \case- DoNothing -> "DO NOTHING"- DoUpdate updates whs'- -> "DO UPDATE SET"- <+> renderCommaSeparated renderUpdate updates- <> case whs' of- [] -> ""- wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)--renderUpdate- :: (forall x. RenderSQL (expr x))- => Aliased (Optional expr) ty- -> ByteString-renderUpdate (expr `As` col) = renderSQL col <+> "=" <+> renderSQL expr---- | A `ConflictTarget` specifies the constraint violation that triggers a--- `ConflictAction`.-data ConflictTarget constraints where- OnConstraint- :: Has con constraints constraint- => Alias con- -> ConflictTarget constraints---- | Render a `ConflictTarget`-instance RenderSQL (ConflictTarget constraints) where- renderSQL (OnConstraint con) =- "ON" <+> "CONSTRAINT" <+> renderSQL con--{------------------------------------------UPDATE statements------------------------------------------}---- | An `update` command changes the values of the specified columns--- in all rows that satisfy the condition.-update- :: ( SOP.SListI columns- , SOP.SListI row1- , db ~ (commons :=> schemas)- , Has sch schemas schema- , Has tab schema ('Table table)- , row0 ~ TableToRow table- , columns ~ TableToColumns table- , SOP.All (HasIn columns) subcolumns- , AllUnique subcolumns )- => QualifiedAlias sch tab -- ^ table to update- -> NP (Aliased (Optional (Expression '[] '[] 'Ungrouped schemas params '[tab ::: row0]))) subcolumns- -- ^ modified values to replace old values- -> Condition '[] commons 'Ungrouped schemas params '[tab ::: row0]- -- ^ condition under which to perform update on a row- -> ReturningClause commons schemas params '[tab ::: row0] row1 -- ^ results to return- -> Manipulation commons schemas params row1-update tab columns wh returning = UnsafeManipulation $- "UPDATE"- <+> renderSQL tab- <+> "SET"- <+> renderCommaSeparated renderUpdate columns- <+> "WHERE" <+> renderSQL wh- <> renderSQL returning---- | Update a row returning `Nil`.-update_- :: ( SOP.SListI columns- , db ~ (commons :=> schemas)- , Has sch schemas schema- , Has tab schema ('Table table)- , row ~ TableToRow table- , columns ~ TableToColumns table- , SOP.All (HasIn columns) subcolumns- , AllUnique subcolumns )- => QualifiedAlias sch tab -- ^ table to update- -> NP (Aliased (Optional (Expression '[] '[] 'Ungrouped schemas params '[tab ::: row]))) subcolumns- -- ^ modified values to replace old values- -> Condition '[] commons 'Ungrouped schemas params '[tab ::: row]- -- ^ condition under which to perform update on a row- -> Manipulation commons schemas params '[]-update_ tab columns wh = update tab columns wh (Returning_ Nil)--{------------------------------------------DELETE statements------------------------------------------}---- | Specify additional tables.-data UsingClause commons schemas params from where- -- | No `UsingClause`- NoUsing :: UsingClause commons schemas params '[]- -- | An `also` list of table expressions, allowing columns- -- from other tables to appear in the WHERE condition.- -- This is similar to the list of tables that can be specified- -- in the FROM Clause of a SELECT statement;- -- for example, an alias for the table name can be specified.- -- Do not repeat the target table in the `Using` list,- -- unless you wish to set up a self-join.- Using- :: FromClause '[] commons schemas params from- -> UsingClause commons schemas params from---- | Delete rows from a table.-deleteFrom- :: ( SOP.SListI row1- , db ~ (commons :=> schemas)- , Has sch schemas schema- , Has tab schema ('Table table)- , row0 ~ TableToRow table- , columns ~ TableToColumns table )- => QualifiedAlias sch tab -- ^ table to delete from- -> UsingClause commons schemas params from- -> Condition '[] commons 'Ungrouped schemas params (tab ::: row0 ': from)- -- ^ condition under which to delete a row- -> ReturningClause commons schemas params '[tab ::: row0] row1 -- ^ results to return- -> Manipulation commons schemas params row1-deleteFrom tab using wh returning = UnsafeManipulation $- "DELETE FROM"- <+> renderSQL tab- <> case using of- NoUsing -> ""- Using tables -> " USING" <+> renderSQL tables- <+> "WHERE" <+> renderSQL wh- <> renderSQL returning---- | Delete rows returning `Nil`.-deleteFrom_- :: ( db ~ (commons :=> schemas)- , Has sch schemas schema- , Has tab schema ('Table table)- , row ~ TableToRow table- , columns ~ TableToColumns table )- => QualifiedAlias sch tab -- ^ table to delete from- -> Condition '[] commons 'Ungrouped schemas params '[tab ::: row]- -- ^ condition under which to delete a row- -> Manipulation commons schemas params '[]-deleteFrom_ tab wh = deleteFrom tab NoUsing wh (Returning_ Nil)
+ src/Squeal/PostgreSQL/Manipulation/Delete.hs view
@@ -0,0 +1,101 @@+{-|+Module: Squeal.PostgreSQL.Delete+Description: delete statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++delete statements+-}++{-# LANGUAGE+ DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , PatternSynonyms+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Manipulation.Delete+ ( -- * Delete+ deleteFrom+ , deleteFrom_+ , UsingClause (..)+ ) where++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Query.From+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{-----------------------------------------+DELETE statements+-----------------------------------------}++-- | Specify additional tables with `Using`+-- an `also` list of table expressions, allowing columns+-- from other tables to appear in the WHERE condition.+-- This is similar to the list of tables that can be specified+-- in the FROM Clause of a SELECT statement;+-- for example, an alias for the table name can be specified.+-- Do not repeat the target table in the `Using` list,+-- unless you wish to set up a self-join.+-- `NoUsing` if no additional tables are to be used.+data UsingClause with db params from where+ NoUsing :: UsingClause with db params '[]+ Using+ :: FromClause '[] with db params from+ -- ^ what to use+ -> UsingClause with db params from++-- | Delete rows from a table.+deleteFrom+ :: ( SOP.SListI row+ , Has sch db schema+ , Has tab schema ('Table table) )+ => QualifiedAlias sch tab -- ^ table to delete from+ -> UsingClause with db params from+ -> Condition 'Ungrouped '[] with db params (tab ::: TableToRow table ': from)+ -- ^ condition under which to delete a row+ -> ReturningClause with db params '[tab ::: TableToRow table] row+ -- ^ results to return+ -> Manipulation with db params row+deleteFrom tab using wh returning = UnsafeManipulation $+ "DELETE FROM"+ <+> renderSQL tab+ <> case using of+ NoUsing -> ""+ Using tables -> " USING" <+> renderSQL tables+ <+> "WHERE" <+> renderSQL wh+ <> renderSQL returning++-- | Delete rows returning `Nil`.+deleteFrom_+ :: ( Has sch db schema+ , Has tab schema ('Table table) )+ => QualifiedAlias sch tab -- ^ table to delete from+ -> Condition 'Ungrouped '[] with db params '[tab ::: TableToRow table]+ -- ^ condition under which to delete a row+ -> Manipulation with db params '[]+deleteFrom_ tab wh = deleteFrom tab NoUsing wh (Returning_ Nil)
+ src/Squeal/PostgreSQL/Manipulation/Insert.hs view
@@ -0,0 +1,259 @@+{-|+Module: Squeal.PostgreSQL.Manipulation.Insert+Description: insert statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++insert statements+-}++{-# LANGUAGE+ DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , PatternSynonyms+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Manipulation.Insert+ ( -- * Insert+ insertInto+ , insertInto_+ -- * Clauses+ , QueryClause (..)+ , pattern Values_+ , inlineValues+ , inlineValues_+ , ConflictClause (..)+ , ConflictTarget (..)+ , ConflictAction (..)+ ) where++import Data.ByteString hiding (foldr)++import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Default+import Squeal.PostgreSQL.Expression.Inline+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Query.Table+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{-----------------------------------------+INSERT statements+-----------------------------------------}++{- |+When a table is created, it contains no data. The first thing to do+before a database can be of much use is to insert data. Data is+conceptually inserted one row at a time. Of course you can also insert+more than one row, but there is no way to insert less than one row.+Even if you know only some column values, a complete row must be created.+-}+insertInto+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , SOP.SListI (TableToColumns table)+ , SOP.SListI row )+ => QualifiedAlias sch tab+ -- ^ table+ -> QueryClause with db params (TableToColumns table)+ -- ^ what to insert+ -> ConflictClause tab with db params table+ -- ^ what to do in case of conflict+ -> ReturningClause with db params '[tab ::: TableToRow table] row+ -- ^ what to return+ -> Manipulation with db params row+insertInto tab qry conflict ret = UnsafeManipulation $+ "INSERT" <+> "INTO" <+> renderSQL tab+ <+> renderSQL qry+ <> renderSQL conflict+ <> renderSQL ret++-- | Like `insertInto` but with `OnConflictDoRaise` and no `ReturningClause`.+insertInto_+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , SOP.SListI (TableToColumns table) )+ => QualifiedAlias sch tab+ -- ^ table+ -> QueryClause with db params (TableToColumns table)+ -- ^ what to insert+ -> Manipulation with db params '[]+insertInto_ tab qry =+ insertInto tab qry OnConflictDoRaise (Returning_ Nil)++-- | A `QueryClause` describes what to `insertInto` a table.+data QueryClause with db params columns where+ Values+ :: SOP.SListI columns+ => NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns+ -- ^ row of values+ -> [NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns]+ -- ^ additional rows of values+ -> QueryClause with db params columns+ Select+ :: SOP.SListI columns+ => NP (Aliased (Optional (Expression grp '[] with db params from))) columns+ -- ^ row of values+ -> TableExpression grp '[] with db params from+ -- ^ from a table expression+ -> QueryClause with db params columns+ Subquery+ :: ColumnsToRow columns ~ row+ => Query '[] with db params row+ -- ^ subquery to insert+ -> QueryClause with db params columns++instance RenderSQL (QueryClause with db params columns) where+ renderSQL = \case+ Values row0 rows ->+ parenthesized (renderCommaSeparated renderSQLPart row0)+ <+> "VALUES"+ <+> commaSeparated+ ( parenthesized+ . renderCommaSeparated renderValuePart <$> row0 : rows )+ Select row0 tab ->+ parenthesized (renderCommaSeparatedMaybe renderSQLPartMaybe row0)+ <+> "SELECT"+ <+> renderCommaSeparatedMaybe renderValuePartMaybe row0+ <+> renderSQL tab+ Subquery qry -> renderQuery qry+ where+ renderSQLPartMaybe, renderValuePartMaybe+ :: Aliased (Optional (Expression grp '[] with db params from)) column+ -> Maybe ByteString+ renderSQLPartMaybe = \case+ Default `As` _ -> Nothing+ Set _ `As` name -> Just $ renderSQL name+ renderValuePartMaybe = \case+ Default `As` _ -> Nothing+ Set value `As` _ -> Just $ renderExpression value+ renderSQLPart, renderValuePart+ :: Aliased (Optional (Expression grp '[] with db params from)) column+ -> ByteString+ renderSQLPart (_ `As` name) = renderSQL name+ renderValuePart (value `As` _) = renderSQL value++-- | `Values_` describes a single `NP` list of `Aliased` `Optional` `Expression`s+-- whose `ColumnsType` must match the tables'.+pattern Values_+ :: SOP.SListI columns+ => NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns+ -- ^ row of values+ -> QueryClause with db params columns+pattern Values_ vals = Values vals []++-- | `inlineValues_` a Haskell record in `insertInto`.+inlineValues_+ :: ( SOP.IsRecord hask xs+ , SOP.AllZip InlineColumn xs columns )+ => hask -- ^ record+ -> QueryClause with db params columns+inlineValues_ = Values_ . inlineColumns++-- | `inlineValues` Haskell records in `insertInto`.+inlineValues+ :: ( SOP.IsRecord hask xs+ , SOP.AllZip InlineColumn xs columns )+ => hask -- ^ record+ -> [hask] -- ^ more+ -> QueryClause with db params columns+inlineValues hask hasks = Values (inlineColumns hask) (inlineColumns <$> hasks)++-- | A `ConflictClause` specifies an action to perform upon a constraint+-- violation. `OnConflictDoRaise` will raise an error.+-- `OnConflict` `DoNothing` simply avoids inserting a row.+-- `OnConflict` `DoUpdate` updates the existing row that conflicts with the row+-- proposed for insertion.+data ConflictClause tab with db params table where+ OnConflictDoRaise :: ConflictClause tab with db params table+ OnConflict+ :: ConflictTarget table+ -- ^ conflict target+ -> ConflictAction tab with db params table+ -- ^ conflict action+ -> ConflictClause tab with db params table++-- | Render a `ConflictClause`.+instance SOP.SListI (TableToColumns table)+ => RenderSQL (ConflictClause tab with db params table) where+ renderSQL = \case+ OnConflictDoRaise -> ""+ OnConflict target action -> " ON CONFLICT"+ <+> renderSQL target <+> renderSQL action++{- |+`ConflictAction` specifies an alternative `OnConflict` action.+It can be either `DoNothing`, or a `DoUpdate` clause specifying+the exact details of the update action to be performed in case of a conflict.+The `Set` and WHERE `Condition`s in `OnConflict` `DoUpdate` have access to the+existing row using the table's name, and to rows proposed+for insertion using the special @#excluded@ row.+`OnConflict` `DoNothing` simply avoids inserting a row as its alternative action.+`OnConflict` `DoUpdate` updates the existing row that conflicts+with the row proposed for insertion as its alternative action.+-}+data ConflictAction tab with db params table where+ DoNothing :: ConflictAction tab with db params table+ DoUpdate+ :: ( row ~ TableToRow table+ , from ~ '[tab ::: row, "excluded" ::: row]+ , Updatable table updates )+ => NP (Aliased (Optional (Expression 'Ungrouped '[] with db params from))) updates+ -> [Condition 'Ungrouped '[] with db params from]+ -- ^ WHERE `Condition`s+ -> ConflictAction tab with db params table++instance RenderSQL (ConflictAction tab with db params table) where+ renderSQL = \case+ DoNothing -> "DO NOTHING"+ DoUpdate updates whs'+ -> "DO UPDATE SET"+ <+> renderCommaSeparated renderUpdate updates+ <> case whs' of+ [] -> ""+ wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)++renderUpdate+ :: (forall x. RenderSQL (expr x))+ => Aliased (Optional expr) ty+ -> ByteString+renderUpdate (expr `As` col) = renderSQL col <+> "=" <+> renderSQL expr++-- | A `ConflictTarget` specifies the constraint violation that triggers a+-- `ConflictAction`.+data ConflictTarget table where+ OnConstraint+ :: Has con constraints constraint+ => Alias con+ -> ConflictTarget (constraints :=> columns)++-- | Render a `ConflictTarget`+instance RenderSQL (ConflictTarget constraints) where+ renderSQL (OnConstraint con) =+ "ON" <+> "CONSTRAINT" <+> renderSQL con
+ src/Squeal/PostgreSQL/Manipulation/Update.hs view
@@ -0,0 +1,97 @@+{-|+Module: Squeal.PostgreSQL.Update+Description: update statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++update statements+-}++{-# LANGUAGE+ DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , PatternSynonyms+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Manipulation.Update+ ( -- * Update+ update+ , update_+ ) where++import Data.ByteString hiding (foldr)++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Default+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++renderUpdate+ :: (forall x. RenderSQL (expr x))+ => Aliased (Optional expr) ty+ -> ByteString+renderUpdate (expr `As` col) = renderSQL col <+> "=" <+> renderSQL expr++{-----------------------------------------+UPDATE statements+-----------------------------------------}++-- | An `update` command changes the values of the specified columns+-- in all rows that satisfy the condition.+update+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , Updatable table updates+ , SOP.SListI row )+ => QualifiedAlias sch tab -- ^ table to update+ -> NP (Aliased (Optional (Expression 'Ungrouped '[] '[] db params '[tab ::: TableToRow table]))) updates+ -- ^ modified values to replace old values+ -> Condition 'Ungrouped '[] with db params '[tab ::: TableToRow table]+ -- ^ condition under which to perform update on a row+ -> ReturningClause with db params '[tab ::: TableToRow table] row -- ^ results to return+ -> Manipulation with db params row+update tab columns wh returning = UnsafeManipulation $+ "UPDATE"+ <+> renderSQL tab+ <+> "SET"+ <+> renderCommaSeparated renderUpdate columns+ <+> "WHERE" <+> renderSQL wh+ <> renderSQL returning++-- | Update a row returning `Nil`.+update_+ :: ( Has sch db schema+ , Has tab schema ('Table table)+ , Updatable table updates )+ => QualifiedAlias sch tab -- ^ table to update+ -> NP (Aliased (Optional (Expression 'Ungrouped '[] '[] db params '[tab ::: TableToRow table]))) updates+ -- ^ modified values to replace old values+ -> Condition 'Ungrouped '[] with db params '[tab ::: TableToRow table]+ -- ^ condition under which to perform update on a row+ -> Manipulation with db params '[]+update_ tab columns wh = update tab columns wh (Returning_ Nil)
− src/Squeal/PostgreSQL/Migration.hs
@@ -1,446 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Migration-Description: Squeal migrations-Copyright: (c) Eitan Chatav, 2017-Maintainer: eitan@morphism.tech-Stability: experimental--This module defines a `Migration` type to safely-change the schema of your database over time. Let's see an example!--First turn on some extensions.-->>> :set -XDataKinds -XOverloadedLabels->>> :set -XOverloadedStrings -XFlexibleContexts -XTypeOperators--Next, let's define our `TableType`s.-->>> :{-type UsersTable =- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "name" ::: 'NoDef :=> 'NotNull 'PGtext- ]-:}-->>> :{-type EmailsTable =- '[ "pk_emails" ::: 'PrimaryKey '["id"]- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]- ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4- , "email" ::: 'NoDef :=> 'Null 'PGtext- ]-:}--Now we can define some `Migration`s to make our tables.-->>> :{-let- makeUsers :: Migration Definition (Public '[]) '["public" ::: '["users" ::: 'Table UsersTable]]- makeUsers = Migration- { name = "make users table"- , up = createTable #users- ( serial `as` #id :*- notNullable text `as` #name )- ( primaryKey #id `as` #pk_users )- , down = dropTable #users- }-:}-->>> :{-let- makeEmails :: Migration Definition '["public" ::: '["users" ::: 'Table UsersTable]]- '["public" ::: '["users" ::: 'Table UsersTable, "emails" ::: 'Table EmailsTable]]- makeEmails = Migration- { name = "make emails table"- , up = createTable #emails- ( serial `as` #id :*- notNullable int `as` #user_id :*- nullable text `as` #email )- ( primaryKey #id `as` #pk_emails :*- foreignKey #user_id #users #id- OnDeleteCascade OnUpdateCascade `as` #fk_user_id )- , down = dropTable #emails- }-:}--Now that we have a couple migrations we can chain them together into an `AlignedList`.-->>> let migrations = makeUsers :>> makeEmails :>> Done--Now run the migrations.-->>> import Control.Monad.IO.Class->>> :{-withConnection "host=localhost port=5432 dbname=exampledb" $- manipulate (UnsafeManipulation "SET client_min_messages TO WARNING;")- -- suppress notices- & pqThen (liftIO (putStrLn "Migrate"))- & pqThen (migrateUp migrations)- & pqThen (liftIO (putStrLn "Rollback"))- & pqThen (migrateDown migrations)-:}-Migrate-Rollback--We can also create a simple executable using `defaultMain`.-->>> let main = defaultMain "host=localhost port=5432 dbname=exampledb" migrations-->>> withArgs [] main-Invalid command: "". Use:-migrate to run all available migrations-rollback to rollback all available migrations-status to display migrations run and migrations left to run-->>> withArgs ["status"] main-Migrations already run:- None-Migrations left to run:- - make users table- - make emails table-->>> withArgs ["migrate"] main-Migrations already run:- - make users table- - make emails table-Migrations left to run:- None-->>> withArgs ["rollback"] main-Migrations already run:- None-Migrations left to run:- - make users table- - make emails table--In addition to enabling `Migration`s using pure SQL `Definition`s for-the `up` and `down` instructions, you can also perform impure `IO` actions-by using a `Migration`s over the `Terminally` `PQ` `IO` category.--}--{-# LANGUAGE- DataKinds- , DeriveGeneric- , FlexibleContexts- , FlexibleInstances- , GADTs- , LambdaCase- , OverloadedLabels- , OverloadedStrings- , PolyKinds- , QuantifiedConstraints- , RankNTypes- , TypeApplications- , TypeOperators-#-}--module Squeal.PostgreSQL.Migration- ( -- * Migration- Migration (..)- , Migratory (..)- , Terminally (..)- , terminally- , pureMigration- , MigrationsTable- , defaultMain- ) where--import Control.Category-import Control.Monad-import Data.ByteString (ByteString)-import Data.Foldable (traverse_)-import Data.Function ((&))-import Data.List ((\\))-import Data.Text (Text)-import Data.Time (UTCTime)-import Prelude hiding ((.), id)-import System.Environment-import UnliftIO (MonadIO (..))--import qualified Data.Text.IO as Text (putStrLn)-import qualified Generics.SOP as SOP-import qualified GHC.Generics as GHC--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.Binary-import Squeal.PostgreSQL.Definition-import Squeal.PostgreSQL.Expression.Comparison-import Squeal.PostgreSQL.Expression.Parameter-import Squeal.PostgreSQL.Expression.Time-import Squeal.PostgreSQL.Expression.Type-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Manipulation-import Squeal.PostgreSQL.PQ-import Squeal.PostgreSQL.Query-import Squeal.PostgreSQL.Schema-import Squeal.PostgreSQL.Transaction---- | A `Migration` is a named "isomorphism" over a given category.--- It should contain an inverse pair of `up` and `down`--- instructions and a unique `name`.-data Migration p schemas0 schemas1 = Migration- { name :: Text -- ^ The `name` of a `Migration`.- -- Each `name` in a `Migration` should be unique.- , up :: p schemas0 schemas1 -- ^ The `up` instruction of a `Migration`.- , down :: p schemas1 schemas0 -- ^ The `down` instruction of a `Migration`.- } deriving (GHC.Generic)--{- |-A `Migratory` @p@ is a `Category` for which one can execute or rewind-an `AlignedList` of `Migration`s over @p@. This includes the category of pure-SQL `Definition`s and the category of impure `Terminally` `PQ` `IO` actions.--}-class Category p => Migratory p where-- {- |- Run an `AlignedList` of `Migration`s.- Create the `MigrationsTable` as @public.schema_migrations@ if it does not already exist.- In one transaction, for each each `Migration` query to see if the `Migration` has been executed;- if not, `up` the `Migration` and insert its `name` in the `MigrationsTable`.- -}- migrateUp- :: AlignedList (Migration p) schemas0 schemas1- -> PQ schemas0 schemas1 IO ()-- {- |- Rewind an `AlignedList` of `Migration`s.- Create the `MigrationsTable` as @public.schema_migrations@ if it does not already exist.- In one transaction, for each each `Migration` query to see if the `Migration` has been executed;- if so, `down` the `Migration` and delete its `name` in the `MigrationsTable`.- -}- migrateDown- :: AlignedList (Migration p) schemas0 schemas1- -> PQ schemas1 schemas0 IO ()--instance Migratory Definition where- migrateUp = migrateUp . mapAligned pureMigration- migrateDown = migrateDown . mapAligned pureMigration--{- | `Terminally` turns an indexed monad transformer and the monad it transforms-into a category by restricting the return type to @()@ and permuting the type variables.-This is similar to how applying a monad to @()@ yields a monoid.-Since a `Terminally` action has a trivial return value, the only reason-to run one is for the side effects, in particular database and other IO effects.--}-newtype Terminally trans monad x0 x1 = Terminally- { runTerminally :: trans x0 x1 monad () }- deriving GHC.Generic--instance- ( IndexedMonadTransPQ trans- , Monad monad- , forall x0 x1. x0 ~ x1 => Monad (trans x0 x1 monad) )- => Category (Terminally trans monad) where- id = Terminally (return ())- Terminally g . Terminally f = Terminally $ pqThen g f---- | `terminally` ignores the output of a computation, returning @()@ and--- wrapping it up into a `Terminally`. You can lift an action in the base monad--- by using @terminally . lift@.-terminally- :: Functor (trans x0 x1 monad)- => trans x0 x1 monad ignore- -> Terminally trans monad x0 x1-terminally = Terminally . void---- | A `pureMigration` turns a `Migration` involving only pure SQL--- `Definition`s into a `Migration` that may be combined with arbitrary `IO`.-pureMigration- :: Migration Definition schemas0 schemas1- -> Migration (Terminally PQ IO) schemas0 schemas1-pureMigration migration = Migration- { name = name migration- , up = terminally . define $ up migration- , down = terminally . define $ down migration- }--instance Migratory (Terminally PQ IO) where-- migrateUp migration = unsafePQ . transactionally_ $ do- define createMigrations- upMigrations migration-- where-- upMigrations- :: AlignedList (Migration (Terminally PQ IO)) schemas0 schemas1- -> PQ MigrationsSchemas MigrationsSchemas IO ()- upMigrations = \case- Done -> return ()- step :>> steps -> upMigration step >> upMigrations steps-- upMigration- :: Migration (Terminally PQ IO) schemas0 schemas1- -> PQ MigrationsSchemas MigrationsSchemas IO ()- upMigration step = do- executed <- queryExecuted step- unless (executed == 1) $ do- unsafePQ . runTerminally $ up step- manipulateParams_ insertMigration (Only (name step))-- queryExecuted- :: Migration (Terminally PQ IO) schemas0 schemas1- -> PQ MigrationsSchemas MigrationsSchemas IO Row- queryExecuted step = do- result <- runQueryParams selectMigration (Only (name step))- ntuples result-- migrateDown migrations = unsafePQ . transactionally_ $ do- define createMigrations- downMigrations migrations-- where-- downMigrations- :: AlignedList (Migration (Terminally PQ IO)) schemas0 schemas1- -> PQ MigrationsSchemas MigrationsSchemas IO ()- downMigrations = \case- Done -> return ()- step :>> steps -> downMigrations steps >> downMigration step-- downMigration- :: Migration (Terminally PQ IO) schemas0 schemas1- -> PQ MigrationsSchemas MigrationsSchemas IO ()- downMigration step = do- executed <- queryExecuted step- unless (executed == 0) $ do- unsafePQ . runTerminally $ down step- manipulateParams_ deleteMigration (Only (name step))-- queryExecuted- :: Migration (Terminally PQ IO) schemas0 schemas1- -> PQ MigrationsSchemas MigrationsSchemas IO Row- queryExecuted step = do- result <- runQueryParams selectMigration (Only (name step))- ntuples result--unsafePQ :: (Functor m) => PQ db0 db1 m x -> PQ db0' db1' m x-unsafePQ (PQ pq) = PQ $ fmap (SOP.K . SOP.unK) . pq . SOP.K . SOP.unK---- | The `TableType` for a Squeal migration.-type MigrationsTable =- '[ "migrations_unique_name" ::: 'Unique '["name"]] :=>- '[ "name" ::: 'NoDef :=> 'NotNull 'PGtext- , "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz- ]--data MigrationRow =- MigrationRow { migrationName :: Text- , migrationTime :: UTCTime }- deriving (GHC.Generic, Show)--instance SOP.Generic MigrationRow-instance SOP.HasDatatypeInfo MigrationRow--type MigrationsSchema = '["schema_migrations" ::: 'Table MigrationsTable]-type MigrationsSchemas = Public MigrationsSchema---- | Creates a `MigrationsTable` if it does not already exist.-createMigrations :: Definition MigrationsSchemas MigrationsSchemas-createMigrations =- createTableIfNotExists #schema_migrations- ( (text & notNullable) `as` #name :*- (timestampWithTimeZone & notNullable & default_ currentTimestamp)- `as` #executed_at )- ( unique #name `as` #migrations_unique_name )---- | Inserts a `Migration` into the `MigrationsTable`, returning--- the time at which it was inserted.-insertMigration :: Manipulation_ MigrationsSchemas (Only Text) ()-insertMigration = insertInto_ #schema_migrations- (Values_ (Set (param @1) `as` #name :* Default `as` #executed_at))---- | Deletes a `Migration` from the `MigrationsTable`, returning--- the time at which it was inserted.-deleteMigration :: Manipulation_ MigrationsSchemas (Only Text) ()-deleteMigration = deleteFrom_ #schema_migrations (#name .== param @1)---- | Selects a `Migration` from the `MigrationsTable`, returning--- the time at which it was inserted.-selectMigration- :: Query_ MigrationsSchemas (Only Text) (Only UTCTime)-selectMigration = select_ (#executed_at `as` #fromOnly)- $ from (table (#schema_migrations))- & where_ (#name .== param @1)--selectMigrations :: Query_ MigrationsSchemas () MigrationRow-selectMigrations = select_- (#name `as` #migrationName :* #executed_at `as` #migrationTime)- (from (table #schema_migrations))--data MigrateCommand- = MigrateStatus- | MigrateUp- | MigrateDown deriving (GHC.Generic, Show)--{- | `defaultMain` creates a simple executable-from a connection string and a list of `Migration`s. -}-defaultMain- :: Migratory p- => ByteString- -- ^ connection string- -> AlignedList (Migration p) db0 db1- -- ^ migrations- -> IO ()-defaultMain connectTo migrations = do- command <- readCommandFromArgs- maybe (pure ()) performCommand command-- where-- performCommand :: MigrateCommand -> IO ()- performCommand = \case- MigrateStatus -> withConnection connectTo $- suppressNotices >> migrateStatus- MigrateUp -> withConnection connectTo $- suppressNotices & pqThen (migrateUp migrations) & pqThen migrateStatus- MigrateDown -> withConnection connectTo $- suppressNotices & pqThen (migrateDown migrations) & pqThen migrateStatus-- migrateStatus :: PQ schema schema IO ()- migrateStatus = unsafePQ $ do- runNames <- getRunMigrationNames- let names = extractList name migrations- unrunNames = names \\ runNames- liftIO $ displayRunned runNames >> displayUnrunned unrunNames-- suppressNotices :: PQ schema schema IO ()- suppressNotices = manipulate_ $- UnsafeManipulation "SET client_min_messages TO WARNING;"-- readCommandFromArgs :: IO (Maybe MigrateCommand)- readCommandFromArgs = getArgs >>= \case- ["migrate"] -> pure . Just $ MigrateUp- ["rollback"] -> pure . Just $ MigrateDown- ["status"] -> pure . Just $ MigrateStatus- args -> displayUsage args >> pure Nothing-- displayUsage :: [String] -> IO ()- displayUsage args = do- putStrLn $ "Invalid command: \"" <> unwords args <> "\". Use:"- putStrLn "migrate to run all available migrations"- putStrLn "rollback to rollback all available migrations"- putStrLn "status to display migrations run and migrations left to run"-- getRunMigrationNames :: (MonadIO m) => PQ db0 db0 m [Text]- getRunMigrationNames =- fmap migrationName <$> (unsafePQ (define createMigrations & pqThen (runQuery selectMigrations)) >>= getRows)-- displayListOfNames :: [Text] -> IO ()- displayListOfNames [] = Text.putStrLn " None"- displayListOfNames xs =- let singleName n = Text.putStrLn $ " - " <> n- in traverse_ singleName xs-- displayUnrunned :: [Text] -> IO ()- displayUnrunned unrunned =- Text.putStrLn "Migrations left to run:"- >> displayListOfNames unrunned-- displayRunned :: [Text] -> IO ()- displayRunned runned =- Text.putStrLn "Migrations already run:"- >> displayListOfNames runned
− src/Squeal/PostgreSQL/PG.hs
@@ -1,365 +0,0 @@-{-|-Module: Squeal.PostgreSQL.PG-Description: Embedding of Haskell types into Postgres's type system-Copyright: (c) Eitan Chatav, 2010-Maintainer: eitan@morphism.tech-Stability: experimental--`Squeal.PostgreSQL.PG` provides type families for turning Haskell-`Type`s into corresponding Postgres types.--}-{-# LANGUAGE- AllowAmbiguousTypes- , DeriveFoldable- , DeriveFunctor- , DeriveGeneric- , DeriveTraversable- , DefaultSignatures- , FlexibleContexts- , FlexibleInstances- , FunctionalDependencies- , GADTs- , LambdaCase- , OverloadedStrings- , MultiParamTypeClasses- , ScopedTypeVariables- , TypeApplications- , TypeFamilies- , TypeInType- , TypeOperators- , UndecidableInstances- , UndecidableSuperClasses-#-}--module Squeal.PostgreSQL.PG- ( -- * PG embeddings- PG- , NullPG- , TuplePG- , RowPG- -- * Storage newtypes- , Money (..)- , Json (..)- , Jsonb (..)- , Composite (..)- , Enumerated (..)- , VarArray (..)- , FixArray (..)- -- * Type families- , LabelsPG- , DimPG- , FixPG- , TupleOf- , TupleCodeOf- , RowOf- , ConstructorsOf- , ConstructorNameOf- , ConstructorNamesOf- ) where--import Data.Aeson (Value)-import Data.Kind (Type)-import Data.Int (Int16, Int32, Int64)-import Data.Scientific (Scientific)-import Data.Time (Day, DiffTime, LocalTime, TimeOfDay, TimeZone, UTCTime)-import Data.Vector (Vector)-import Data.Word (Word16, Word32, Word64)-import Data.UUID.Types (UUID)-import GHC.TypeLits-import Network.IP.Addr (NetAddr, IP)--import qualified Data.ByteString.Lazy as Lazy (ByteString)-import qualified Data.ByteString as Strict (ByteString)-import qualified Data.Text.Lazy as Lazy (Text)-import qualified Data.Text as Strict (Text)-import qualified GHC.Generics as GHC-import qualified Generics.SOP as SOP-import qualified Generics.SOP.Record as SOP-import qualified Generics.SOP.Type.Metadata as Type--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.Schema---- $setup--- >>> import Squeal.PostgreSQL--- >>> import Data.Text (Text)--{- | The `PG` type family embeds a subset of Haskell types-as Postgres types. As an open type family, `PG` is extensible.-->>> :kind! PG LocalTime-PG LocalTime :: PGType-= 'PGtimestamp-->>> newtype MyDouble = My Double->>> :set -XTypeFamilies->>> type instance PG MyDouble = 'PGfloat8--}-type family PG (hask :: Type) :: PGType--- | `PGbool`-type instance PG Bool = 'PGbool--- | `PGint2`-type instance PG Int16 = 'PGint2--- | `PGint4`-type instance PG Int32 = 'PGint4--- | `PGint8`-type instance PG Int64 = 'PGint8--- | `PGint2`-type instance PG Word16 = 'PGint2--- | `PGint4`-type instance PG Word32 = 'PGint4--- | `PGint8`-type instance PG Word64 = 'PGint8--- | `PGnumeric`-type instance PG Scientific = 'PGnumeric--- | `PGfloat4`-type instance PG Float = 'PGfloat4--- | `PGfloat8`-type instance PG Double = 'PGfloat8--- | `PGchar` @1@-type instance PG Char = 'PGchar 1--- | `PGtext`-type instance PG Strict.Text = 'PGtext--- | `PGtext`-type instance PG Lazy.Text = 'PGtext--- | `PGtext`-type instance PG String = 'PGtext--- | `PGbytea`-type instance PG Strict.ByteString = 'PGbytea--- | `PGbytea`-type instance PG Lazy.ByteString = 'PGbytea--- | `PGtimestamp`-type instance PG LocalTime = 'PGtimestamp--- | `PGtimestamptz`-type instance PG UTCTime = 'PGtimestamptz--- | `PGdate`-type instance PG Day = 'PGdate--- | `PGtime`-type instance PG TimeOfDay = 'PGtime--- | `PGtimetz`-type instance PG (TimeOfDay, TimeZone) = 'PGtimetz--- | `PGinterval`-type instance PG DiffTime = 'PGinterval--- | `PGuuid`-type instance PG UUID = 'PGuuid--- | `PGinet`-type instance PG (NetAddr IP) = 'PGinet--- | `PGjson`-type instance PG Value = 'PGjson--{-| The `LabelsPG` type family calculates the constructors of a-Haskell enum type.-->>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic->>> instance SOP.Generic Schwarma->>> instance SOP.HasDatatypeInfo Schwarma->>> :kind! LabelsPG Schwarma-LabelsPG Schwarma :: [Type.ConstructorName]-= '["Beef", "Lamb", "Chicken"]--}-type family LabelsPG (hask :: Type) :: [Type.ConstructorName] where- LabelsPG hask =- ConstructorNamesOf (ConstructorsOf (SOP.DatatypeInfoOf hask))--{- |-`RowPG` turns a Haskell `Type` into a `RowType`.--`RowPG` may be applied to normal Haskell record types provided they-have `SOP.Generic` and `SOP.HasDatatypeInfo` instances;-->>> data Person = Person { name :: Strict.Text, age :: Int32 } deriving GHC.Generic->>> instance SOP.Generic Person->>> instance SOP.HasDatatypeInfo Person->>> :kind! RowPG Person-RowPG Person :: [(Symbol, NullityType)]-= '["name" ::: 'NotNull 'PGtext, "age" ::: 'NotNull 'PGint4]--}-type family RowPG (hask :: Type) :: RowType where- RowPG hask = RowOf (SOP.RecordCodeOf hask)---- | `RowOf` applies `NullPG` to the fields of a list.-type family RowOf (record :: [(Symbol, Type)]) :: RowType where- RowOf '[] = '[]- RowOf (col ::: ty ': record) = col ::: NullPG ty ': RowOf record--{- | `NullPG` turns a Haskell type into a `NullityType`.-->>> :kind! NullPG Double-NullPG Double :: NullityType-= 'NotNull 'PGfloat8->>> :kind! NullPG (Maybe Double)-NullPG (Maybe Double) :: NullityType-= 'Null 'PGfloat8--}-type family NullPG (hask :: Type) :: NullityType where- NullPG (Maybe hask) = 'Null (PG hask)- NullPG hask = 'NotNull (PG hask)--{- | `TuplePG` turns a Haskell tuple type (including record types) into-the corresponding list of `NullityType`s.-->>> :kind! TuplePG (Double, Maybe Char)-TuplePG (Double, Maybe Char) :: [NullityType]-= '[ 'NotNull 'PGfloat8, 'Null ('PGchar 1)]--}-type family TuplePG (hask :: Type) :: [NullityType] where- TuplePG hask = TupleOf (TupleCodeOf hask (SOP.Code hask))---- | `TupleOf` turns a list of Haskell `Type`s into a list of `NullityType`s.-type family TupleOf (tuple :: [Type]) :: [NullityType] where- TupleOf '[] = '[]- TupleOf (hask ': tuple) = NullPG hask ': TupleOf tuple---- | `TupleCodeOf` takes the `SOP.Code` of a haskell `Type`--- and if it's a simple product returns it, otherwise giving a `TypeError`.-type family TupleCodeOf (hask :: Type) (code :: [[Type]]) :: [Type] where- TupleCodeOf hask '[tuple] = tuple- TupleCodeOf hask '[] =- TypeError- ( 'Text "The type `" ':<>: 'ShowType hask ':<>: 'Text "' is not a tuple type."- ':$$: 'Text "It is a void type with no constructors."- )- TupleCodeOf hask (_ ': _ ': _) =- TypeError- ( 'Text "The type `" ':<>: 'ShowType hask ':<>: 'Text "' is not a tuple type."- ':$$: 'Text "It is a sum type with more than one constructor."- )---- | Calculates constructors of a datatype.-type family ConstructorsOf (datatype :: Type.DatatypeInfo)- :: [Type.ConstructorInfo] where- ConstructorsOf ('Type.ADT _module _datatype constructors) =- constructors- ConstructorsOf ('Type.Newtype _module _datatype constructor) =- '[constructor]---- | Calculates the name of a nullary constructor, otherwise--- generates a type error.-type family ConstructorNameOf (constructor :: Type.ConstructorInfo)- :: Type.ConstructorName where- ConstructorNameOf ('Type.Constructor name) = name- ConstructorNameOf ('Type.Infix name _assoc _fix) = TypeError- ('Text "ConstructorNameOf error: non-nullary constructor "- ':<>: 'Text name)- ConstructorNameOf ('Type.Record name _fields) = TypeError- ('Text "ConstructorNameOf error: non-nullary constructor "- ':<>: 'Text name)---- | Calculate the names of nullary constructors.-type family ConstructorNamesOf (constructors :: [Type.ConstructorInfo])- :: [Type.ConstructorName] where- ConstructorNamesOf '[] = '[]- ConstructorNamesOf (constructor ': constructors) =- ConstructorNameOf constructor ': ConstructorNamesOf constructors---- | `DimPG` turns Haskell nested homogeneous tuples into a list of lengths.-type family DimPG (hask :: Type) :: [Nat] where- DimPG (x,x) = 2 ': DimPG x- DimPG (x,x,x) = 3 ': DimPG x- DimPG (x,x,x,x) = 4 ': DimPG x- DimPG (x,x,x,x,x) = 5 ': DimPG x- DimPG (x,x,x,x,x,x) = 6 ': DimPG x- DimPG (x,x,x,x,x,x,x) = 7 ': DimPG x- DimPG (x,x,x,x,x,x,x,x) = 8 ': DimPG x- DimPG (x,x,x,x,x,x,x,x,x) = 9 ': DimPG x- DimPG (x,x,x,x,x,x,x,x,x,x) = 10 ': DimPG x- DimPG x = '[]---- | `FixPG` extracts `NullPG` of the base type of nested homogeneous tuples.-type family FixPG (hask :: Type) :: NullityType where- FixPG (x,x) = FixPG x- FixPG (x,x,x) = FixPG x- FixPG (x,x,x,x) = FixPG x- FixPG (x,x,x,x,x) = FixPG x- FixPG (x,x,x,x,x,x) = FixPG x- FixPG (x,x,x,x,x,x,x) = FixPG x- FixPG (x,x,x,x,x,x,x,x) = FixPG x- FixPG (x,x,x,x,x,x,x,x,x) = FixPG x- FixPG (x,x,x,x,x,x,x,x,x,x) = FixPG x- FixPG (x,x,x,x,x,x,x,x,x,x,x) = FixPG x- FixPG x = NullPG x--{- | The `Money` newtype stores a monetary value in terms-of the number of cents, i.e. @$2,000.20@ would be expressed as-@Money { cents = 200020 }@.-->>> import Control.Monad (void)->>> import Control.Monad.IO.Class (liftIO)->>> import Squeal.PostgreSQL->>> :{-let- roundTrip :: Query_ (Public '[]) (Only Money) (Only Money)- roundTrip = values_ $ parameter @1 money `as` #fromOnly-:}-->>> let input = Only (Money 20020)-->>> :{-withConnection "host=localhost port=5432 dbname=exampledb" $ do- result <- runQueryParams roundTrip input- Just output <- firstRow result- liftIO . print $ input == output-:}-True--}-newtype Money = Money { cents :: Int64 }- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGmoney`-type instance PG Money = 'PGmoney--{- | The `Json` newtype is an indication that the Haskell-type it's applied to should be stored as a `PGjson`.--}-newtype Json hask = Json {getJson :: hask}- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGjson`-type instance PG (Json hask) = 'PGjson--{- | The `Jsonb` newtype is an indication that the Haskell-type it's applied to should be stored as a `PGjsonb`.--}-newtype Jsonb hask = Jsonb {getJsonb :: hask}- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGjsonb`-type instance PG (Jsonb hask) = 'PGjsonb--{- | The `Composite` newtype is an indication that the Haskell-type it's applied to should be stored as a `PGcomposite`.--}-newtype Composite record = Composite {getComposite :: record}- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGcomposite` @(@`RowPG` @hask)@-type instance PG (Composite hask) = 'PGcomposite (RowPG hask)--{- | The `Enumerated` newtype is an indication that the Haskell-type it's applied to should be stored as a `PGenum`.--}-newtype Enumerated enum = Enumerated {getEnumerated :: enum}- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGenum` @(@`LabelsPG` @hask)@-type instance PG (Enumerated hask) = 'PGenum (LabelsPG hask)--{- | The `VarArray` newtype is an indication that the Haskell-type it's applied to should be stored as a `PGvararray`.-->>> :kind! PG (VarArray (Vector Double))-PG (VarArray (Vector Double)) :: PGType-= 'PGvararray ('NotNull 'PGfloat8)--}-newtype VarArray arr = VarArray {getVarArray :: arr}- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGvararray` @(@`NullPG` @hask)@-type instance PG (VarArray (Vector hask)) = 'PGvararray (NullPG hask)-type instance PG (VarArray [hask]) = 'PGvararray (NullPG hask)--{- | The `FixArray` newtype is an indication that the Haskell-type it's applied to should be stored as a `PGfixarray`.-->>> :kind! PG (FixArray ((Double, Double), (Double, Double)))-PG (FixArray ((Double, Double), (Double, Double))) :: PGType-= 'PGfixarray '[2, 2] ('NotNull 'PGfloat8)--}-newtype FixArray arr = FixArray {getFixArray :: arr}- deriving (Eq, Ord, Show, Read, GHC.Generic)--- | `PGfixarray` @(@`DimPG` @hask) (@`FixPG` @hask)@-type instance PG (FixArray hask) = 'PGfixarray (DimPG hask) (FixPG hask)
− src/Squeal/PostgreSQL/PQ.hs
@@ -1,688 +0,0 @@-{-|-Module: Squeal.PostgreSQL.PQ-Description: PQ monad-Copyright: (c) Eitan Chatav, 2017-Maintainer: eitan@morphism.tech-Stability: experimental--This module is where Squeal commands actually get executed by-`Database.PostgreSQL.LibPQ`. It containts two typeclasses, `IndexedMonadTransPQ` for executing-a `Definition` and `MonadPQ` for executing a `Manipulation` or `Query`,-and a `PQ` type with instances for them.--Using Squeal in your application will come down to defining-the @schemas@ of your database and including @PQ schemas schemas@ in your-application's monad transformer stack, giving it an instance of `MonadPQ`.--This module also provides functions for retrieving rows from the `LibPQ.Result`-of executing Squeal commands.--}--{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}-{-# LANGUAGE- DefaultSignatures- , FunctionalDependencies- , FlexibleContexts- , FlexibleInstances- , InstanceSigs- , OverloadedStrings- , RankNTypes- , ScopedTypeVariables- , TypeApplications- , TypeFamilies- , TypeInType- , TypeOperators- , UndecidableInstances-#-}--module Squeal.PostgreSQL.PQ- ( -- * Connection- LibPQ.Connection- , connectdb- , finish- , withConnection- , lowerConnection- -- * PQ- , PQ (PQ, unPQ)- , runPQ- , execPQ- , evalPQ- , IndexedMonadTransPQ (..)- , MonadPQ (..)- -- * Results- , LibPQ.Result- , LibPQ.Row- , ntuples- , getRow- , getRows- , nextRow- , firstRow- , liftResult- , LibPQ.ExecStatus (..)- , resultStatus- , resultErrorMessage- , resultErrorCode- -- * Exceptions- , SquealException (..)- , PQState (..)- , okResult- , catchSqueal- , handleSqueal- , trySqueal- ) where--import Control.Exception (Exception, throw)-import Control.Monad.Except-import Control.Monad.Morph-import UnliftIO (MonadUnliftIO (..), bracket, catch, handle, try)-import Data.ByteString (ByteString)-import Data.Foldable-import Data.Function ((&))-import Data.Kind-import Data.Text (pack, Text)-import Data.Traversable-import Generics.SOP-import PostgreSQL.Binary.Encoding (encodingBytes)--import qualified Control.Monad.Fail as Fail-import qualified Database.PostgreSQL.LibPQ as LibPQ--import Squeal.PostgreSQL.Binary-import Squeal.PostgreSQL.Definition-import Squeal.PostgreSQL.Manipulation-import Squeal.PostgreSQL.Query-import Squeal.PostgreSQL.Schema---- For `MonadPQ` transformer instances-import Control.Monad.Trans.Identity-import Control.Monad.Trans.Reader-import Control.Monad.Trans.Maybe-import Control.Monad.Trans.Cont--import qualified Control.Monad.Trans.State.Lazy as Lazy-import qualified Control.Monad.Trans.State.Strict as Strict-import qualified Control.Monad.Trans.Writer.Lazy as Lazy-import qualified Control.Monad.Trans.Writer.Strict as Strict-import qualified Control.Monad.Trans.RWS.Lazy as Lazy-import qualified Control.Monad.Trans.RWS.Strict as Strict---- $setup--- >>> import Squeal.PostgreSQL--{- | Makes a new connection to the database server.--This function opens a new database connection using the parameters taken-from the string conninfo.--The passed string can be empty to use all default parameters, or it can-contain one or more parameter settings separated by whitespace.-Each parameter setting is in the form keyword = value. Spaces around the equal-sign are optional. To write an empty value or a value containing spaces,-surround it with single quotes, e.g., keyword = 'a value'. Single quotes and-backslashes within the value must be escaped with a backslash, i.e., ' and \.--To specify the schema you wish to connect with, use type application.-->>> :set -XDataKinds->>> :set -XPolyKinds->>> :set -XTypeOperators->>> type Schema = '["tab" ::: '[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint2]]->>> :set -XTypeApplications->>> :set -XOverloadedStrings->>> conn <- connectdb @Schema "host=localhost port=5432 dbname=exampledb"--Note that, for now, squeal doesn't offer any protection from connecting-with the wrong schema!--}-connectdb- :: forall schemas io- . MonadIO io- => ByteString -- ^ conninfo- -> io (K LibPQ.Connection schemas)-connectdb = fmap K . liftIO . LibPQ.connectdb---- | Closes the connection to the server.-finish :: MonadIO io => K LibPQ.Connection schemas -> io ()-finish = liftIO . LibPQ.finish . unK---- | Do `connectdb` and `finish` before and after a computation.-withConnection- :: forall schemas0 schemas1 io x- . MonadUnliftIO io- => ByteString- -> PQ schemas0 schemas1 io x- -> io x-withConnection connString action = do- K x <- bracket (connectdb connString) finish (unPQ action)- return x---- | Safely `lowerConnection` to a smaller schema.-lowerConnection- :: K LibPQ.Connection (schema ': schemas)- -> K LibPQ.Connection schemas-lowerConnection (K conn) = K conn---- | We keep track of the schema via an Atkey indexed state monad transformer,--- `PQ`.-newtype PQ- (schemas0 :: SchemasType)- (schemas1 :: SchemasType)- (m :: Type -> Type)- (x :: Type) =- PQ { unPQ :: K LibPQ.Connection schemas0 -> m (K x schemas1) }--instance Monad m => Functor (PQ schemas0 schemas1 m) where- fmap f (PQ pq) = PQ $ \ conn -> do- K x <- pq conn- return $ K (f x)---- | Run a `PQ` and keep the result and the `LibPQ.Connection`.-runPQ- :: Functor m- => PQ schemas0 schemas1 m x- -> K LibPQ.Connection schemas0- -> m (x, K LibPQ.Connection schemas1)-runPQ (PQ pq) conn = (\ x -> (unK x, K (unK conn))) <$> pq conn- -- K x <- pq conn- -- return (x, K (unK conn))---- | Execute a `PQ` and discard the result but keep the `LibPQ.Connection`.-execPQ- :: Functor m- => PQ schemas0 schemas1 m x- -> K LibPQ.Connection schemas0- -> m (K LibPQ.Connection schemas1)-execPQ (PQ pq) conn = mapKK (\ _ -> unK conn) <$> pq conn---- | Evaluate a `PQ` and discard the `LibPQ.Connection` but keep the result.-evalPQ- :: Functor m- => PQ schemas0 schemas1 m x- -> K LibPQ.Connection schemas0- -> m x-evalPQ (PQ pq) conn = unK <$> pq conn---- | An [Atkey indexed monad](https://bentnib.org/paramnotions-jfp.pdf) is a `Functor`--- [enriched category](https://ncatlab.org/nlab/show/enriched+category).--- An indexed monad transformer transforms a `Monad` into an indexed monad.--- And, `IndexedMonadTransPQ` is a class for indexed monad transformers that--- support running `Definition`s using `define`.-class IndexedMonadTransPQ pq where-- -- | indexed analog of `<*>`- pqAp- :: Monad m- => pq schemas0 schemas1 m (x -> y)- -> pq schemas1 schemas2 m x- -> pq schemas0 schemas2 m y-- -- | indexed analog of `join`- pqJoin- :: Monad m- => pq schemas0 schemas1 m (pq schemas1 schemas2 m y)- -> pq schemas0 schemas2 m y- pqJoin pq = pq & pqBind id-- -- | indexed analog of `=<<`- pqBind- :: Monad m- => (x -> pq schemas1 schemas2 m y)- -> pq schemas0 schemas1 m x- -> pq schemas0 schemas2 m y-- -- | indexed analog of flipped `>>`- pqThen- :: Monad m- => pq schemas1 schemas2 m y- -> pq schemas0 schemas1 m x- -> pq schemas0 schemas2 m y- pqThen pq2 pq1 = pq1 & pqBind (\ _ -> pq2)-- -- | indexed analog of `<=<`- pqAndThen- :: Monad m- => (y -> pq schemas1 schemas2 m z)- -> (x -> pq schemas0 schemas1 m y)- -> x -> pq schemas0 schemas2 m z- pqAndThen g f x = pqBind g (f x)-- -- | Run a `Definition` with `LibPQ.exec`.- --- -- It should be functorial in effect.- --- -- @define id = return ()@- -- @define (statement1 >>> statement2) = define statement1 & pqThen (define statement2)@- define- :: MonadIO io- => Definition schemas0 schemas1- -> pq schemas0 schemas1 io ()--instance IndexedMonadTransPQ PQ where-- pqAp (PQ f) (PQ x) = PQ $ \ conn -> do- K f' <- f conn- K x' <- x (K (unK conn))- return $ K (f' x')-- pqBind f (PQ x) = PQ $ \ conn -> do- K x' <- x conn- unPQ (f x') (K (unK conn))-- define (UnsafeDefinition q) = PQ $ \ (K conn) -> do- resultMaybe <- liftIO $ LibPQ.exec conn q- case resultMaybe of- Nothing -> throw $ ResultException- "define: LibPQ.exec returned no results"- Just result -> K <$> okResult_ result--{- | `MonadPQ` is an @mtl@ style constraint, similar to-`Control.Monad.State.Class.MonadState`, for using `Database.PostgreSQL.LibPQ` to--* `manipulateParams` runs a `Manipulation` with params from a type- with a `ToParams` constraint. It calls `LibPQ.execParams` and- doesn't afraid of anything.--* `manipulateParams_` is like `manipulateParams` for a returning-free statement.--* `manipulate` is like `manipulateParams` for a parameter-free statement.--* `manipulate_` is like `manipulate` for a returning-free statement.--* `runQueryParams` is like `manipulateParams` for query statements.--* `runQuery` is like `runQueryParams` for a parameter-free statement.--* `traversePrepared` has the same type signature as a composition of- `traverse` and `manipulateParams` but provides an optimization by- preparing the statement with `LibPQ.prepare` and then traversing a- `Traversable` container with `LibPQ.execPrepared`. The temporary prepared- statement is then deallocated.--* `forPrepared` is a flipped `traversePrepared`--* `traversePrepared_` is like `traversePrepared` but works on `Foldable`- containers for a returning-free statement.--* `forPrepared_` is a flipped `traversePrepared_`.--* `liftPQ` lets you lift actions from `Database.PostgreSQL.LibPQ` that require a connection- into your monad.--To define an instance, you can minimally define only `manipulateParams`,-`traversePrepared`, `traversePrepared_` and `liftPQ`. Monad transformers get-a default instance.---}-class Monad pq => MonadPQ schemas pq | pq -> schemas where- manipulateParams- :: ToParams x params- => Manipulation '[] schemas params ys- -- ^ `insertInto`, `update` or `deleteFrom`- -> x -> pq (K LibPQ.Result ys)- default manipulateParams- :: (MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1)- => ToParams x params- => Manipulation '[] schemas params ys- -- ^ `insertInto`, `update` or `deleteFrom`- -> x -> pq (K LibPQ.Result ys)- manipulateParams manipulation params = lift $- manipulateParams manipulation params-- manipulateParams_- :: ToParams x params- => Manipulation '[] schemas params '[]- -- ^ `insertInto`, `update` or `deleteFrom`- -> x -> pq ()- manipulateParams_ q x = void $ manipulateParams q x-- manipulate :: Manipulation '[] schemas '[] ys -> pq (K LibPQ.Result ys)- manipulate statement = manipulateParams statement ()-- manipulate_ :: Manipulation '[] schemas '[] '[] -> pq ()- manipulate_ = void . manipulate-- runQueryParams- :: ToParams x params- => Query '[] '[] schemas params ys- -- ^ `select` and friends- -> x -> pq (K LibPQ.Result ys)- runQueryParams = manipulateParams . queryStatement-- runQuery- :: Query '[] '[] schemas '[] ys- -- ^ `select` and friends- -> pq (K LibPQ.Result ys)- runQuery q = runQueryParams q ()-- traversePrepared- :: (ToParams x params, Traversable list)- => Manipulation '[] schemas params ys- -- ^ `insertInto`, `update`, or `deleteFrom`, and friends- -> list x -> pq (list (K LibPQ.Result ys))- default traversePrepared- :: (MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1)- => (ToParams x params, Traversable list)- => Manipulation '[] schemas params ys -> list x -> pq (list (K LibPQ.Result ys))- traversePrepared manipulation params = lift $- traversePrepared manipulation params-- forPrepared- :: (ToParams x params, Traversable list)- => list x- -> Manipulation '[] schemas params ys- -- ^ `insertInto`, `update` or `deleteFrom`- -> pq (list (K LibPQ.Result ys))- forPrepared = flip traversePrepared-- traversePrepared_- :: (ToParams x params, Foldable list)- => Manipulation '[] schemas params '[]- -- ^ `insertInto`, `update` or `deleteFrom`- -> list x -> pq ()- default traversePrepared_- :: (MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1)- => (ToParams x params, Foldable list)- => Manipulation '[] schemas params '[]- -- ^ `insertInto`, `update` or `deleteFrom`- -> list x -> pq ()- traversePrepared_ manipulation params = lift $- traversePrepared_ manipulation params-- forPrepared_- :: (ToParams x params, Foldable list)- => list x- -> Manipulation '[] schemas params '[]- -- ^ `insertInto`, `update` or `deleteFrom`- -> pq ()- forPrepared_ = flip traversePrepared_-- liftPQ :: (LibPQ.Connection -> IO a) -> pq a- default liftPQ- :: (MonadTrans t, MonadPQ schemas pq1, pq ~ t pq1)- => (LibPQ.Connection -> IO a) -> pq a- liftPQ = lift . liftPQ--instance (MonadIO io, schemas0 ~ schemas, schemas1 ~ schemas)- => MonadPQ schemas (PQ schemas0 schemas1 io) where-- manipulateParams- (UnsafeManipulation q :: Manipulation '[] schemas ps ys) (params :: x) =- PQ $ \ (K conn) -> do- let- toParam' encoding =- (LibPQ.invalidOid, encodingBytes encoding, LibPQ.Binary)- params' = fmap (fmap toParam') (hcollapse (toParams @x @ps params))- q' = q <> ";"- resultMaybe <- liftIO $ LibPQ.execParams conn q' params' LibPQ.Binary- case resultMaybe of- Nothing -> throw $ ResultException- "manipulateParams: LibPQ.execParams returned no results"- Just result -> do- okResult_ result- return $ K (K result)-- traversePrepared- (UnsafeManipulation q :: Manipulation '[] schemas xs ys) (list :: list x) =- PQ $ \ (K conn) -> liftIO $ do- let temp = "temporary_statement"- prepResultMaybe <- LibPQ.prepare conn temp q Nothing- case prepResultMaybe of- Nothing -> throw $ ResultException- "traversePrepared: LibPQ.prepare returned no results"- Just prepResult -> okResult_ prepResult- results <- for list $ \ params -> do- let- toParam' encoding = (encodingBytes encoding,LibPQ.Binary)- params' = fmap (fmap toParam') (hcollapse (toParams @x @xs params))- resultMaybe <- LibPQ.execPrepared conn temp params' LibPQ.Binary- case resultMaybe of- Nothing -> throw $ ResultException- "traversePrepared: LibPQ.execParams returned no results"- Just result -> do- okResult_ result- return $ K result- deallocResultMaybe <- LibPQ.exec conn ("DEALLOCATE " <> temp <> ";")- case deallocResultMaybe of- Nothing -> throw $ ResultException- "traversePrepared: LibPQ.exec DEALLOCATE returned no results"- Just deallocResult -> okResult_ deallocResult- return (K results)-- traversePrepared_- (UnsafeManipulation q :: Manipulation '[] schemas xs '[]) (list :: list x) =- PQ $ \ (K conn) -> liftIO $ do- let temp = "temporary_statement"- prepResultMaybe <- LibPQ.prepare conn temp q Nothing- case prepResultMaybe of- Nothing -> throw $ ResultException- "traversePrepared_: LibPQ.prepare returned no results"- Just prepResult -> okResult_ prepResult- for_ list $ \ params -> do- let- toParam' encoding = (encodingBytes encoding, LibPQ.Binary)- params' = fmap (fmap toParam') (hcollapse (toParams @x @xs params))- resultMaybe <- LibPQ.execPrepared conn temp params' LibPQ.Binary- case resultMaybe of- Nothing -> throw $ ResultException- "traversePrepared_: LibPQ.execParams returned no results"- Just result -> okResult_ result- deallocResultMaybe <- LibPQ.exec conn ("DEALLOCATE " <> temp <> ";")- case deallocResultMaybe of- Nothing -> throw $ ResultException- "traversePrepared: LibPQ.exec DEALLOCATE returned no results"- Just deallocResult -> okResult_ deallocResult- return (K ())-- liftPQ pq = PQ $ \ (K conn) -> do- y <- liftIO $ pq conn- return (K y)--instance MonadPQ schemas m => MonadPQ schemas (IdentityT m)-instance MonadPQ schemas m => MonadPQ schemas (ReaderT r m)-instance MonadPQ schemas m => MonadPQ schemas (Strict.StateT s m)-instance MonadPQ schemas m => MonadPQ schemas (Lazy.StateT s m)-instance (Monoid w, MonadPQ schemas m) => MonadPQ schemas (Strict.WriterT w m)-instance (Monoid w, MonadPQ schemas m) => MonadPQ schemas (Lazy.WriterT w m)-instance MonadPQ schemas m => MonadPQ schemas (MaybeT m)-instance MonadPQ schemas m => MonadPQ schemas (ExceptT e m)-instance (Monoid w, MonadPQ schemas m) => MonadPQ schemas (Strict.RWST r w s m)-instance (Monoid w, MonadPQ schemas m) => MonadPQ schemas (Lazy.RWST r w s m)-instance MonadPQ schemas m => MonadPQ schemas (ContT r m)--instance (Monad m, schemas0 ~ schemas1)- => Applicative (PQ schemas0 schemas1 m) where- pure x = PQ $ \ _conn -> pure (K x)- (<*>) = pqAp--instance (Monad m, schemas0 ~ schemas1)- => Monad (PQ schemas0 schemas1 m) where- return = pure- (>>=) = flip pqBind--instance (Monad m, schemas0 ~ schemas1)- => Fail.MonadFail (PQ schemas0 schemas1 m) where- fail = Fail.fail--instance schemas0 ~ schemas1 => MFunctor (PQ schemas0 schemas1) where- hoist f (PQ pq) = PQ (f . pq)--instance schemas0 ~ schemas1 => MonadTrans (PQ schemas0 schemas1) where- lift m = PQ $ \ _conn -> do- x <- m- return (K x)--instance schemas0 ~ schemas1 => MMonad (PQ schemas0 schemas1) where- embed f (PQ pq) = PQ $ \ conn -> do- evalPQ (f (pq conn)) conn--instance (MonadIO m, schema0 ~ schema1)- => MonadIO (PQ schema0 schema1 m) where- liftIO = lift . liftIO--instance (MonadUnliftIO m, schemas0 ~ schemas1)- => MonadUnliftIO (PQ schemas0 schemas1 m) where- withRunInIO- :: ((forall a . PQ schemas0 schema1 m a -> IO a) -> IO b)- -> PQ schemas0 schema1 m b- withRunInIO inner = PQ $ \conn ->- withRunInIO $ \(run :: (forall x . m x -> IO x)) ->- K <$> inner (\pq -> run $ unK <$> unPQ pq conn)---- | Get a row corresponding to a given row number from a `LibPQ.Result`,--- throwing an exception if the row number is out of bounds.-getRow- :: (FromRow columns y, MonadIO io)- => LibPQ.Row- -- ^ row number- -> K LibPQ.Result columns- -- ^ result- -> io y-getRow r (K result :: K LibPQ.Result columns) = liftIO $ do- numRows <- LibPQ.ntuples result- when (numRows < r) $ throw $ ResultException $- "getRow: expected at least " <> pack (show r) <> "rows but only saw "- <> pack (show numRows)- let len = fromIntegral (lengthSList (Proxy @columns))- row' <- traverse (LibPQ.getvalue result r) [0 .. len - 1]- case fromList row' of- Nothing -> throw $ ResultException "getRow: found unexpected length"- Just row -> case fromRow @columns row of- Left parseError -> throw $ ParseException $ "getRow: " <> parseError- Right y -> return y---- | Intended to be used for unfolding in streaming libraries, `nextRow`--- takes a total number of rows (which can be found with `ntuples`)--- and a `LibPQ.Result` and given a row number if it's too large returns `Nothing`,--- otherwise returning the row along with the next row number.-nextRow- :: (FromRow columns y, MonadIO io)- => LibPQ.Row -- ^ total number of rows- -> K LibPQ.Result columns -- ^ result- -> LibPQ.Row -- ^ row number- -> io (Maybe (LibPQ.Row,y))-nextRow total (K result :: K LibPQ.Result columns) r- = liftIO $ if r >= total then return Nothing else do- let len = fromIntegral (lengthSList (Proxy @columns))- row' <- traverse (LibPQ.getvalue result r) [0 .. len - 1]- case fromList row' of- Nothing -> throw $ ResultException "nextRow: found unexpected length"- Just row -> case fromRow @columns row of- Left parseError -> throw $ ParseException $ "nextRow: " <> parseError- Right y -> return $ Just (r+1, y)---- | Get all rows from a `LibPQ.Result`.-getRows- :: (FromRow columns y, MonadIO io)- => K LibPQ.Result columns -- ^ result- -> io [y]-getRows (K result :: K LibPQ.Result columns) = liftIO $ do- let len = fromIntegral (lengthSList (Proxy @columns))- numRows <- LibPQ.ntuples result- for [0 .. numRows - 1] $ \ r -> do- row' <- traverse (LibPQ.getvalue result r) [0 .. len - 1]- case fromList row' of- Nothing -> throw $ ResultException "getRows: found unexpected length"- Just row -> case fromRow @columns row of- Left parseError -> throw $ ParseException $ "getRows: " <> parseError- Right y -> return y---- | Get the first row if possible from a `LibPQ.Result`.-firstRow- :: (FromRow columns y, MonadIO io)- => K LibPQ.Result columns -- ^ result- -> io (Maybe y)-firstRow (K result :: K LibPQ.Result columns) = liftIO $ do- numRows <- LibPQ.ntuples result- if numRows <= 0 then return Nothing else do- let len = fromIntegral (lengthSList (Proxy @columns))- row' <- traverse (LibPQ.getvalue result 0) [0 .. len - 1]- case fromList row' of- Nothing -> throw $ ResultException "firstRow: found unexpected length"- Just row -> case fromRow @columns row of- Left parseError -> throw $ ParseException $ "firstRow: " <> parseError- Right y -> return $ Just y---- | Lifts actions on results from @LibPQ@.-liftResult- :: MonadIO io- => (LibPQ.Result -> IO x)- -> K LibPQ.Result results -> io x-liftResult f (K result) = liftIO $ f result---- | Returns the number of rows (tuples) in the query result.-ntuples :: MonadIO io => K LibPQ.Result columns -> io LibPQ.Row-ntuples = liftResult LibPQ.ntuples---- | Returns the result status of the command.-resultStatus :: MonadIO io => K LibPQ.Result results -> io LibPQ.ExecStatus-resultStatus = liftResult LibPQ.resultStatus---- | Returns the error message most recently generated by an operation--- on the connection.-resultErrorMessage- :: MonadIO io => K LibPQ.Result results -> io (Maybe ByteString)-resultErrorMessage = liftResult LibPQ.resultErrorMessage---- | Returns the error code most recently generated by an operation--- on the connection.------ https://www.postgresql.org/docs/current/static/errcodes-appendix.html-resultErrorCode- :: MonadIO io- => K LibPQ.Result results- -> io (Maybe ByteString)-resultErrorCode = liftResult (flip LibPQ.resultErrorField LibPQ.DiagSqlstate)---- | the state of LibPQ-data PQState = PQState- { sqlExecStatus :: LibPQ.ExecStatus- , sqlStateCode :: Maybe ByteString- -- ^ https://www.postgresql.org/docs/current/static/errcodes-appendix.html- , sqlErrorMessage :: Maybe ByteString- } deriving (Eq, Show)---- | `Exception`s that can be thrown by Squeal.-data SquealException- = PQException PQState- | ResultException Text- | ParseException Text- deriving (Eq, Show)-instance Exception SquealException--okResult_ :: MonadIO io => LibPQ.Result -> io ()-okResult_ result = liftIO $ do- status <- LibPQ.resultStatus result- case status of- LibPQ.CommandOk -> return ()- LibPQ.TuplesOk -> return ()- _ -> do- stateCode <- LibPQ.resultErrorField result LibPQ.DiagSqlstate- msg <- LibPQ.resultErrorMessage result- throw . PQException $ PQState status stateCode msg---- | Check if a `LibPQ.Result`'s status is either `LibPQ.CommandOk`--- or `LibPQ.TuplesOk` otherwise `throw` a `PQException`.-okResult :: MonadIO io => K LibPQ.Result row -> io ()-okResult = okResult_ . unK---- | Catch `SquealException`s.-catchSqueal- :: MonadUnliftIO io- => io a- -> (SquealException -> io a) -- ^ handler- -> io a-catchSqueal = catch---- | Handle `SquealException`s.-handleSqueal- :: MonadUnliftIO io- => (SquealException -> io a) -- ^ handler- -> io a -> io a-handleSqueal = handle---- | `Either` return a `SquealException` or a result.-trySqueal- :: MonadUnliftIO io- => io a- -> io (Either SquealException a)-trySqueal = try
− src/Squeal/PostgreSQL/Pool.hs
@@ -1,122 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Pool-Description: Connection pools-Copyright: (c) Eitan Chatav, 2017-Maintainer: eitan@morphism.tech-Stability: experimental--Connection pools.--Typical use case would be to create your pool using `createConnectionPool`-and run anything that requires the pool connection with `usingConnectionPool`.--Here's a simplified example:-->>> import Squeal.PostgreSQL-->>> :{-do- let- query :: Query_ (Public '[]) () (Only Char)- query = values_ (literal 'a' `as` #fromOnly)- pool <- createConnectionPool "host=localhost port=5432 dbname=exampledb" 1 0.5 10- chr <- usingConnectionPool pool $ do- result <- runQuery query- Just (Only a) <- firstRow result- return a- destroyConnectionPool pool- putChar chr-:}-a--}--{-# LANGUAGE- DeriveFunctor- , FlexibleContexts- , FlexibleInstances- , InstanceSigs- , MultiParamTypeClasses- , RankNTypes- , ScopedTypeVariables- , TypeFamilies- , TypeInType- , UndecidableInstances-#-}--module Squeal.PostgreSQL.Pool- ( -- * Pools- Pool- , createConnectionPool- , usingConnectionPool- , destroyConnectionPool- ) where--import Data.ByteString-import Data.Time-import Generics.SOP (K(..), unK)-import UnliftIO (MonadUnliftIO (..))-import UnliftIO.Pool (Pool, createPool, destroyAllResources, withResource)--import Squeal.PostgreSQL.PQ---- | Create a striped pool of connections.--- Although the garbage collector will destroy all idle connections when the pool is garbage collected it's recommended to manually `destroyAllResources` when you're done with the pool so that the connections are freed up as soon as possible.-createConnectionPool- :: MonadUnliftIO io- => ByteString- -- ^ The passed string can be empty to use all default parameters, or it can- -- contain one or more parameter settings separated by whitespace.- -- Each parameter setting is in the form keyword = value. Spaces around the equal- -- sign are optional. To write an empty value or a value containing spaces,- -- surround it with single quotes, e.g., keyword = 'a value'. Single quotes and- -- backslashes within the value must be escaped with a backslash, i.e., ' and \.- -> Int- -- ^ The number of stripes (distinct sub-pools) to maintain. The smallest acceptable value is 1.- -> NominalDiffTime- -- ^ Amount of time for which an unused connection is kept open. The smallest acceptable value is 0.5 seconds.- -- The elapsed time before destroying a connection may be a little longer than requested, as the reaper thread wakes at 1-second intervals.- -> Int- -- ^ Maximum number of connections to keep open per stripe. The smallest acceptable value is 1.- -- Requests for connections will block if this limit is reached on a single stripe, even if other stripes have idle connections available.- -> io (Pool (K Connection schemas))-createConnectionPool conninfo stripes idle maxResrc =- createPool (connectdb conninfo) finish stripes idle maxResrc--{-|-Temporarily take a connection from a `Pool`, perform an action with it,-and return it to the pool afterwards.--If the pool has an idle connection available, it is used immediately.-Otherwise, if the maximum number of connections has not yet been reached,-a new connection is created and used.-If the maximum number of connections has been reached, this function blocks-until a connection becomes available.--}-usingConnectionPool- :: MonadUnliftIO io- => Pool (K Connection schemas) -- ^ pool- -> PQ schemas schemas io x -- ^ session- -> io x-usingConnectionPool pool (PQ session) = unK <$> withResource pool session--{- |-Destroy all connections in all stripes in the pool.-Note that this will ignore any exceptions in the destroy function.--This function is useful when you detect that all connections-in the pool are broken. For example after a database has been-restarted all connections opened before the restart will be broken.-In that case it's better to close those connections so that-`usingConnectionPool` won't take a broken connection from the pool-but will open a new connection instead.--Another use-case for this function is that when you know you are done-with the pool you can destroy all idle connections immediately-instead of waiting on the garbage collector to destroy them,-thus freeing up those connections sooner.--}-destroyConnectionPool- :: MonadUnliftIO io- => Pool (K Connection schemas) -- ^ pool- -> io ()-destroyConnectionPool = destroyAllResources
src/Squeal/PostgreSQL/Query.hs view
@@ -1,16 +1,17 @@ {-| Module: Squeal.PostgreSQL.Query-Description: Squeal queries+Description: structured query language Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Squeal queries.+structured query language -} {-# LANGUAGE ConstraintKinds , DeriveGeneric+ , DerivingStrategies , FlexibleContexts , FlexibleInstances , GADTs@@ -31,18 +32,9 @@ #-} module Squeal.PostgreSQL.Query- ( -- * Queries+ ( -- * Query Query_ , Query (..)- -- ** Select- , select- , select_- , selectDistinct- , selectDistinct_- , Selection (..)- -- ** Values- , values- , values_ -- ** Set Operations , union , unionAll@@ -50,54 +42,17 @@ , intersectAll , except , exceptAll- -- ** With- , With (..)- , CommonTableExpression (..)- , withRecursive- -- * Table Expressions- , TableExpression (..)- , from- , where_- , groupBy- , having- , limit- , offset- -- * From Clauses- , FromClause (..)- , table- , subquery- , view- , common- , crossJoin- , innerJoin- , leftOuterJoin- , rightOuterJoin- , fullOuterJoin- -- * Grouping- , By (..)- , GroupByClause (..)- , HavingClause (..) ) where import Control.DeepSeq import Data.ByteString (ByteString) import Data.Kind (Type)-import Data.String-import Data.Word-import Generics.SOP hiding (from)-import GHC.TypeLits import qualified GHC.Generics as GHC -import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.Expression-import Squeal.PostgreSQL.Expression.Logic-import Squeal.PostgreSQL.Expression.Sort-import Squeal.PostgreSQL.Expression.Window-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.PG+import Squeal.PostgreSQL.Type.PG import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.Schema+import Squeal.PostgreSQL.Type.Schema -- $setup -- >>> import Squeal.PostgreSQL@@ -112,32 +67,40 @@ The general `Query` type is parameterized by -* @outer :: FromType@ - outer scope for a correlated subquery,-* @commons :: FromType@ - scope for all `common` table expressions,-* @schemas :: SchemasType@ - scope for all `table`s and `view`s,-* @params :: [NullityType]@ - scope for all `Squeal.Expression.Parameter.parameter`s,++* @with :: FromType@ - scope for all `Squeal.PostgreSQL.Query.From.common` table expressions,+* @db :: SchemasType@ - scope for all `Squeal.PostgreSQL.Query.From.table`s and `Squeal.PostgreSQL.Query.From.view`s,+* @params :: [NullType]@ - scope for all `Squeal.Expression.Parameter.parameter`s, * @row :: RowType@ - return type of the `Query`. -} newtype Query- (outer :: FromType)- (commons :: FromType)- (schemas :: SchemasType)- (params :: [NullityType])+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType]) (row :: RowType) = UnsafeQuery { renderQuery :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL (Query outer commons schemas params row) where renderSQL = renderQuery+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (Query lat with db params row) where renderSQL = renderQuery {- |-The top level `Query_` type is parameterized by a @schemas@ `SchemasType`,-against which the query is type-checked, an input @parameters@ Haskell `Type`,+The top level `Query_` type is parameterized by a @db@ `SchemasType`,+against which the query is type-checked, an input @params@ Haskell `Type`, and an ouput row Haskell `Type`. -A top-level query can be run-using `Squeal.PostgreSQL.PQ.runQueryParams`, or if @parameters = ()@-using `Squeal.PostgreSQL.PQ.runQuery`.+`Query_` is a type family which resolves into a `Query`,+so don't be fooled by the input params and output row Haskell `Type`s,+which are converted into appropriate+Postgres @[@`NullType`@]@ params and `RowType` rows.+Use a top-level `Squeal.PostgreSQL.Session.Statement.Statement` to+fix actual Haskell input params and output rows. -Generally, @parameters@ will be a Haskell tuple or record whose entries+A top-level `Query_` can be run+using `Squeal.PostgreSQL.Session.runQueryParams`, or if @params = ()@+using `Squeal.PostgreSQL.Session.runQuery`.++Generally, @params@ will be a Haskell tuple or record whose entries may be referenced using positional `Squeal.PostgreSQL.Expression.Parameter.parameter`s and @row@ will be a Haskell record, whose entries will be targeted using overloaded labels.@@ -175,7 +138,7 @@ & where_ (#col2 .> 0) ) in printSQL query :}-SELECT ("col1" + "col2") AS "col1", "col1" AS "col2" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > 0))+SELECT ("col1" + "col2") AS "col1", "col1" AS "col2" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > (0 :: int4))) subquery: @@ -219,7 +182,7 @@ & having (sum_ (Distinct #col2) .> 1) ) in printSQL query :}-SELECT COALESCE(sum(ALL "col2"), 0) AS "col1", "col1" AS "col2" FROM "tab" AS "table1" GROUP BY "col1" HAVING (sum(DISTINCT "col2") > 1)+SELECT COALESCE(sum(ALL "col2"), (0 :: int8)) AS "col1", "col1" AS "col2" FROM "tab" AS "table1" GROUP BY "col1" HAVING (sum(DISTINCT "col2") > (1 :: int8)) sorted query: @@ -284,6 +247,22 @@ :} SELECT "o"."price" AS "price", "c"."name" AS "customerName", "s"."name" AS "shipperName" FROM "orders" AS "o" INNER JOIN "customers" AS "c" ON ("o"."customer_id" = "c"."id") INNER JOIN "shippers" AS "s" ON ("o"."shipper_id" = "s"."id") +>>> :{+let+ query :: Query_ (Public OrdersSchema) () Order+ query = select_+ ( #o ! #price `as` #price :*+ #c ! #name `as` #customerName :*+ #s ! #name `as` #shipperName )+ ( from (table (#orders `as` #o)+ & (inner.JoinLateral) (select Star (from (table #customers)) `as` #c)+ (#o ! #customer_id .== #c ! #id)+ & (inner.JoinLateral) (select Star (from (table #shippers)) `as` #s)+ (#o ! #shipper_id .== #s ! #id)) )+in printSQL query+:}+SELECT "o"."price" AS "price", "c"."name" AS "customerName", "s"."name" AS "shipperName" FROM "orders" AS "o" INNER JOIN LATERAL (SELECT * FROM "customers" AS "customers") AS "c" ON ("o"."customer_id" = "c"."id") INNER JOIN LATERAL (SELECT * FROM "shippers" AS "shippers") AS "s" ON ("o"."shipper_id" = "s"."id")+ self-join: >>> :{@@ -300,13 +279,13 @@ >>> :{ let- query :: Query_ schemas () (Row String Bool)+ query :: Query_ db () (Row String Bool) query = values ("true" `as` #col1 :* true `as` #col2) ["false" `as` #col1 :* false `as` #col2] in printSQL query :}-SELECT * FROM (VALUES (E'true', TRUE), (E'false', FALSE)) AS t ("col1", "col2")+SELECT * FROM (VALUES ((E'true' :: text), TRUE), ((E'false' :: text), FALSE)) AS t ("col1", "col2") set operations: @@ -359,18 +338,18 @@ -} type family Query_- (schemas :: SchemasType)- (parameters :: Type)+ (db :: SchemasType)+ (params :: Type) (row :: Type) where- Query_ schemas params row =- Query '[] '[] schemas (TuplePG params) (RowPG row)+ Query_ db params row =+ Query '[] '[] db (TuplePG params) (RowPG row) -- | The results of two queries can be combined using the set operation -- `union`. Duplicate rows are eliminated. union- :: Query outer commons schemas params columns- -> Query outer commons schemas params columns- -> Query outer commons schemas params columns+ :: Query lat with db params columns+ -> Query lat with db params columns+ -> Query lat with db params columns q1 `union` q2 = UnsafeQuery $ parenthesized (renderSQL q1) <+> "UNION"@@ -379,9 +358,9 @@ -- | The results of two queries can be combined using the set operation -- `unionAll`, the disjoint union. Duplicate rows are retained. unionAll- :: Query outer commons schemas params columns- -> Query outer commons schemas params columns- -> Query outer commons schemas params columns+ :: Query lat with db params columns+ -> Query lat with db params columns+ -> Query lat with db params columns q1 `unionAll` q2 = UnsafeQuery $ parenthesized (renderSQL q1) <+> "UNION" <+> "ALL"@@ -390,9 +369,9 @@ -- | The results of two queries can be combined using the set operation -- `intersect`, the intersection. Duplicate rows are eliminated. intersect- :: Query outer commons schemas params columns- -> Query outer commons schemas params columns- -> Query outer commons schemas params columns+ :: Query lat with db params columns+ -> Query lat with db params columns+ -> Query lat with db params columns q1 `intersect` q2 = UnsafeQuery $ parenthesized (renderSQL q1) <+> "INTERSECT"@@ -401,9 +380,9 @@ -- | The results of two queries can be combined using the set operation -- `intersectAll`, the intersection. Duplicate rows are retained. intersectAll- :: Query outer commons schemas params columns- -> Query outer commons schemas params columns- -> Query outer commons schemas params columns+ :: Query lat with db params columns+ -> Query lat with db params columns+ -> Query lat with db params columns q1 `intersectAll` q2 = UnsafeQuery $ parenthesized (renderSQL q1) <+> "INTERSECT" <+> "ALL"@@ -412,9 +391,9 @@ -- | The results of two queries can be combined using the set operation -- `except`, the set difference. Duplicate rows are eliminated. except- :: Query outer commons schemas params columns- -> Query outer commons schemas params columns- -> Query outer commons schemas params columns+ :: Query lat with db params columns+ -> Query lat with db params columns+ -> Query lat with db params columns q1 `except` q2 = UnsafeQuery $ parenthesized (renderSQL q1) <+> "EXCEPT"@@ -423,624 +402,10 @@ -- | The results of two queries can be combined using the set operation -- `exceptAll`, the set difference. Duplicate rows are retained. exceptAll- :: Query outer commons schemas params columns- -> Query outer commons schemas params columns- -> Query outer commons schemas params columns+ :: Query lat with db params columns+ -> Query lat with db params columns+ -> Query lat with db params columns q1 `exceptAll` q2 = UnsafeQuery $ parenthesized (renderSQL q1) <+> "EXCEPT" <+> "ALL" <+> parenthesized (renderSQL q2)--{------------------------------------------SELECT queries------------------------------------------}--{- | The simplest kinds of `Selection` are `Star` and `DotStar` which-emits all columns that a `TableExpression` produces. A select `List`-is a list of `Expression`s. A `Selection` could be a list of-`WindowFunction`s `Over` `WindowDefinition`. `Additional` `Selection`s can-be selected with `Also`.--}-data Selection outer commons grp schemas params from row where- Star- :: HasUnique tab from row- => Selection outer commons 'Ungrouped schemas params from row- -- ^ `HasUnique` table in the `FromClause`- DotStar- :: Has tab from row- => Alias tab- -- ^ `Has` table with `Alias`- -> Selection outer commons 'Ungrouped schemas params from row- List- :: SListI row- => NP (Aliased (Expression outer commons grp schemas params from)) row- -- ^ `NP` list of `Aliased` `Expression`s- -> Selection outer commons grp schemas params from row- Over- :: SListI row- => NP (Aliased (WindowFunction outer commons grp schemas params from)) row- -- ^ `NP` list of `Aliased` `WindowFunction`s- -> WindowDefinition outer commons grp schemas params from- -> Selection outer commons grp schemas params from row- Also- :: Selection outer commons grp schemas params from right- -- ^ `Additional` `Selection`- -> Selection outer commons grp schemas params from left- -> Selection outer commons grp schemas params from (Join left right)-instance Additional (Selection outer commons grp schemas params from) where- also = Also-instance (KnownSymbol col, row ~ '[col ::: ty])- => Aliasable col- (Expression outer commons grp schemas params from ty)- (Selection outer commons grp schemas params from row) where- expr `as` col = List (expr `as` col)-instance (Has tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])- => IsQualified tab col- (Selection outer commons 'Ungrouped schemas params from row1) where- tab ! col = tab ! col `as` col-instance- ( Has tab (Join outer from) row0- , Has col row0 ty- , row1 ~ '[col ::: ty]- , GroupedBy tab col bys )- => IsQualified tab col- (Selection outer commons ('Grouped bys) schemas params from row1) where- tab ! col = tab ! col `as` col-instance (HasUnique tab (Join outer from) row0, Has col row0 ty, row1 ~ '[col ::: ty])- => IsLabel col- (Selection outer commons 'Ungrouped schemas params from row1) where- fromLabel = fromLabel @col `as` Alias-instance- ( HasUnique tab (Join outer from) row0- , Has col row0 ty- , row1 ~ '[col ::: ty]- , GroupedBy tab col bys )- => IsLabel col- (Selection outer commons ('Grouped bys) schemas params from row1) where- fromLabel = fromLabel @col `as` Alias--instance RenderSQL (Selection outer commons grp schemas params from row) where- renderSQL = \case- List list -> renderCommaSeparated (renderAliased renderSQL) list- Star -> "*"- DotStar tab -> renderSQL tab <> ".*"- Also right left -> renderSQL left <> ", " <> renderSQL right- Over winFns winDef ->- let- renderOver- :: Aliased (WindowFunction outer commons grp schemas params from) field- -> ByteString- renderOver (winFn `As` col) = renderSQL winFn- <+> "OVER" <+> parenthesized (renderSQL winDef)- <+> "AS" <+> renderSQL col- in- renderCommaSeparated renderOver winFns--instance IsString- (Selection outer commons grp schemas params from '["fromOnly" ::: 'NotNull 'PGtext]) where- fromString str = fromString str `as` Alias---- | the `TableExpression` in the `select` command constructs an intermediate--- virtual table by possibly combining tables, views, eliminating rows,--- grouping, etc. This table is finally passed on to processing by--- the select list. The `Selection` determines which columns of--- the intermediate table are actually output.-select- :: (SListI row, row ~ (x ': xs))- => Selection outer commons grp schemas params from row- -- ^ selection- -> TableExpression outer commons grp schemas params from- -- ^ intermediate virtual table- -> Query outer commons schemas params row-select selection tabexpr = UnsafeQuery $- "SELECT"- <+> renderSQL selection- <+> renderSQL tabexpr---- | Like `select` but takes an `NP` list of `Expression`s instead--- of a general `Selection`.-select_- :: (SListI row, row ~ (x ': xs))- => NP (Aliased (Expression outer commons grp schemas params from)) row- -- ^ select list- -> TableExpression outer commons grp schemas params from- -- ^ intermediate virtual table- -> Query outer commons schemas params row-select_ = select . List---- | After the select list has been processed, the result table can--- be subject to the elimination of duplicate rows using `selectDistinct`.-selectDistinct- :: (SListI columns, columns ~ (col ': cols))- => Selection outer commons 'Ungrouped schemas params from columns- -- ^ selection- -> TableExpression outer commons 'Ungrouped schemas params from- -- ^ intermediate virtual table- -> Query outer commons schemas params columns-selectDistinct selection tabexpr = UnsafeQuery $- "SELECT DISTINCT"- <+> renderSQL selection- <+> renderSQL tabexpr---- | Like `selectDistinct` but takes an `NP` list of `Expression`s instead--- of a general `Selection`.-selectDistinct_- :: (SListI columns, columns ~ (col ': cols))- => NP (Aliased (Expression outer commons 'Ungrouped schemas params from)) columns- -- ^ select list- -> TableExpression outer commons 'Ungrouped schemas params from- -- ^ intermediate virtual table- -> Query outer commons schemas params columns-selectDistinct_ = selectDistinct . List---- | `values` computes a row value or set of row values--- specified by value expressions. It is most commonly used--- to generate a “constant table” within a larger command,--- but it can be used on its own.------ >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]--- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query outer commons schemas '[] Row--- >>> printSQL query--- SELECT * FROM (VALUES (1, E'one')) AS t ("a", "b")-values- :: SListI cols- => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols- -> [NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols]- -- ^ When more than one row is specified, all the rows must- -- must have the same number of elements- -> Query outer commons schemas params cols-values rw rws = UnsafeQuery $ "SELECT * FROM"- <+> parenthesized (- "VALUES"- <+> commaSeparated- ( parenthesized- . renderCommaSeparated renderValuePart <$> rw:rws )- ) <+> "AS t"- <+> parenthesized (renderCommaSeparated renderAliasPart rw)- where- renderAliasPart, renderValuePart- :: Aliased (Expression outer commons 'Ungrouped schemas params '[] ) ty -> ByteString- renderAliasPart (_ `As` name) = renderSQL name- renderValuePart (value `As` _) = renderSQL value---- | `values_` computes a row value or set of row values--- specified by value expressions.-values_- :: SListI cols- => NP (Aliased (Expression outer commons 'Ungrouped schemas params '[] )) cols- -- ^ one row of values- -> Query outer commons schemas params cols-values_ rw = values rw []--{------------------------------------------Table Expressions------------------------------------------}---- | A `TableExpression` computes a table. The table expression contains--- a `fromClause` that is optionally followed by a `whereClause`,--- `groupByClause`, `havingClause`, `orderByClause`, `limitClause`--- and `offsetClause`s. Trivial table expressions simply refer--- to a table on disk, a so-called base table, but more complex expressions--- can be used to modify or combine base tables in various ways.-data TableExpression- (outer :: FromType)- (commons :: FromType)- (grp :: Grouping)- (schemas :: SchemasType)- (params :: [NullityType])- (from :: FromType)- = TableExpression- { fromClause :: FromClause outer commons schemas params from- -- ^ A table reference that can be a table name, or a derived table such- -- as a subquery, a @JOIN@ construct, or complex combinations of these.- , whereClause :: [Condition outer commons 'Ungrouped schemas params from]- -- ^ optional search coditions, combined with `.&&`. After the processing- -- of the `fromClause` is done, each row of the derived virtual table- -- is checked against the search condition. If the result of the- -- condition is true, the row is kept in the output table,- -- otherwise it is discarded. The search condition typically references- -- at least one column of the table generated in the `fromClause`;- -- this is not required, but otherwise the WHERE clause will- -- be fairly useless.- , groupByClause :: GroupByClause grp from- -- ^ The `groupByClause` is used to group together those rows in a table- -- that have the same values in all the columns listed. The order in which- -- the columns are listed does not matter. The effect is to combine each- -- set of rows having common values into one group row that represents all- -- rows in the group. This is done to eliminate redundancy in the output- -- and/or compute aggregates that apply to these groups.- , havingClause :: HavingClause outer commons grp schemas params from- -- ^ If a table has been grouped using `groupBy`, but only certain groups- -- are of interest, the `havingClause` can be used, much like a- -- `whereClause`, to eliminate groups from the result. Expressions in the- -- `havingClause` can refer both to grouped expressions and to ungrouped- -- expressions (which necessarily involve an aggregate function).- , orderByClause :: [SortExpression outer commons grp schemas params from]- -- ^ The `orderByClause` is for optional sorting. When more than one- -- `SortExpression` is specified, the later (right) values are used to sort- -- rows that are equal according to the earlier (left) values.- , limitClause :: [Word64]- -- ^ The `limitClause` is combined with `min` to give a limit count- -- if nonempty. If a limit count is given, no more than that many rows- -- will be returned (but possibly fewer, if the query itself yields- -- fewer rows).- , offsetClause :: [Word64]- -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count- -- if nonempty. The offset count says to skip that many rows before- -- beginning to return rows. The rows are skipped before the limit count- -- is applied.- } deriving (GHC.Generic)---- | Render a `TableExpression`-instance RenderSQL (TableExpression outer commons grp schemas params from) where- renderSQL- (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat- [ "FROM ", renderSQL frm'- , renderWheres whs'- , renderSQL grps'- , renderSQL hvs'- , renderOrderByClause srts'- , renderLimits lims'- , renderOffsets offs' ]- where- renderWheres = \case- [] -> ""- wh:[] -> " WHERE" <+> renderSQL wh- wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)- renderOrderByClause = \case- [] -> ""- srts -> " ORDER BY"- <+> commaSeparated (renderSQL <$> srts)- renderLimits = \case- [] -> ""- lims -> " LIMIT" <+> fromString (show (minimum lims))- renderOffsets = \case- [] -> ""- offs -> " OFFSET" <+> fromString (show (sum offs))---- | A `from` generates a `TableExpression` from a table reference that can be--- a table name, or a derived table such as a subquery, a JOIN construct,--- or complex combinations of these. A `from` may be transformed by `where_`,--- `groupBy`, `having`, `orderBy`, `limit` and `offset`, using the `&` operator--- to match the left-to-right sequencing of their placement in SQL.-from- :: FromClause outer commons schemas params from -- ^ table reference- -> TableExpression outer commons 'Ungrouped schemas params from-from tab = TableExpression tab [] NoGroups NoHaving [] [] []---- | A `where_` is an endomorphism of `TableExpression`s which adds a--- search condition to the `whereClause`.-where_- :: Condition outer commons 'Ungrouped schemas params from -- ^ filtering condition- -> TableExpression outer commons grp schemas params from- -> TableExpression outer commons grp schemas params from-where_ wh rels = rels {whereClause = wh : whereClause rels}---- | A `groupBy` is a transformation of `TableExpression`s which switches--- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform--- a "grand total" aggregation query.-groupBy- :: SListI bys- => NP (By from) bys -- ^ grouped columns- -> TableExpression outer commons 'Ungrouped schemas params from- -> TableExpression outer commons ('Grouped bys) schemas params from-groupBy bys rels = TableExpression- { fromClause = fromClause rels- , whereClause = whereClause rels- , groupByClause = Group bys- , havingClause = Having []- , orderByClause = []- , limitClause = limitClause rels- , offsetClause = offsetClause rels- }---- | A `having` is an endomorphism of `TableExpression`s which adds a--- search condition to the `havingClause`.-having- :: Condition outer commons ('Grouped bys) schemas params from -- ^ having condition- -> TableExpression outer commons ('Grouped bys) schemas params from- -> TableExpression outer commons ('Grouped bys) schemas params from-having hv rels = rels- { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }--instance OrderBy TableExpression where- orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}---- | A `limit` is an endomorphism of `TableExpression`s which adds to the--- `limitClause`.-limit- :: Word64 -- ^ limit parameter- -> TableExpression outer commons grp schemas params from- -> TableExpression outer commons grp schemas params from-limit lim rels = rels {limitClause = lim : limitClause rels}---- | An `offset` is an endomorphism of `TableExpression`s which adds to the--- `offsetClause`.-offset- :: Word64 -- ^ offset parameter- -> TableExpression outer commons grp schemas params from- -> TableExpression outer commons grp schemas params from-offset off rels = rels {offsetClause = off : offsetClause rels}--{------------------------------------------FROM clauses------------------------------------------}--{- |-A `FromClause` can be a table name, or a derived table such-as a subquery, a @JOIN@ construct, or complex combinations of these.--}-newtype FromClause outer commons schemas params from- = UnsafeFromClause { renderFromClause :: ByteString }- deriving (GHC.Generic,Show,Eq,Ord,NFData)-instance RenderSQL (FromClause outer commons schemas params from) where- renderSQL = renderFromClause---- | A real `table` is a table from the database.-table- :: (Has sch schemas schema, Has tab schema ('Table table))- => Aliased (QualifiedAlias sch) (alias ::: tab)- -> FromClause outer commons schemas params '[alias ::: TableToRow table]-table (tab `As` alias) = UnsafeFromClause $- renderSQL tab <+> "AS" <+> renderSQL alias---- | `subquery` derives a table from a `Query`.-subquery- :: Aliased (Query outer commons schemas params) query- -> FromClause outer commons schemas params '[query]-subquery = UnsafeFromClause . renderAliased (parenthesized . renderSQL)---- | `view` derives a table from a `View`.-view- :: (Has sch schemas schema, Has vw schema ('View view))- => Aliased (QualifiedAlias sch) (alias ::: vw)- -> FromClause outer commons schemas params '[alias ::: view]-view (vw `As` alias) = UnsafeFromClause $- renderSQL vw <+> "AS" <+> renderSQL alias---- | `common` derives a table from a common table expression.-common- :: Has cte commons common- => Aliased Alias (alias ::: cte)- -> FromClause outer commons schemas params '[alias ::: common]-common (cte `As` alias) = UnsafeFromClause $- renderSQL cte <+> "AS" <+> renderSQL alias--instance Additional (FromClause outer commons schemas params) where- also right left = UnsafeFromClause $- renderSQL left <> ", " <> renderSQL right--{- |-@left & crossJoin right@. For every possible combination of rows from-@left@ and @right@ (i.e., a Cartesian product), the joined table will contain-a row consisting of all columns in @left@ followed by all columns in @right@.-If the tables have @n@ and @m@ rows respectively, the joined table will-have @n * m@ rows.--}-crossJoin- :: FromClause outer commons schemas params right- -- ^ right- -> FromClause outer commons schemas params left- -- ^ left- -> FromClause outer commons schemas params (Join left right)-crossJoin right left = UnsafeFromClause $- renderSQL left <+> "CROSS JOIN" <+> renderSQL right--{- | @left & innerJoin right on@. The joined table is filtered by-the @on@ condition.--}-innerJoin- :: FromClause outer commons schemas params right- -- ^ right- -> Condition outer commons 'Ungrouped schemas params (Join left right)- -- ^ @on@ condition- -> FromClause outer commons schemas params left- -- ^ left- -> FromClause outer commons schemas params (Join left right)-innerJoin right on left = UnsafeFromClause $- renderSQL left <+> "INNER JOIN" <+> renderSQL right- <+> "ON" <+> renderSQL on--{- | @left & leftOuterJoin right on@. First, an inner join is performed.- Then, for each row in @left@ that does not satisfy the @on@ condition with- any row in @right@, a joined row is added with null values in columns of @right@.- Thus, the joined table always has at least one row for each row in @left@.--}-leftOuterJoin- :: FromClause outer commons schemas params right- -- ^ right- -> Condition outer commons 'Ungrouped schemas params (Join left right)- -- ^ @on@ condition- -> FromClause outer commons schemas params left- -- ^ left- -> FromClause outer commons schemas params (Join left (NullifyFrom right))-leftOuterJoin right on left = UnsafeFromClause $- renderSQL left <+> "LEFT OUTER JOIN" <+> renderSQL right- <+> "ON" <+> renderSQL on--{- | @left & rightOuterJoin right on@. First, an inner join is performed.- Then, for each row in @right@ that does not satisfy the @on@ condition with- any row in @left@, a joined row is added with null values in columns of @left@.- This is the converse of a left join: the result table will always- have a row for each row in @right@.--}-rightOuterJoin- :: FromClause outer commons schemas params right- -- ^ right- -> Condition outer commons 'Ungrouped schemas params (Join left right)- -- ^ @on@ condition- -> FromClause outer commons schemas params left- -- ^ left- -> FromClause outer commons schemas params (Join (NullifyFrom left) right)-rightOuterJoin right on left = UnsafeFromClause $- renderSQL left <+> "RIGHT OUTER JOIN" <+> renderSQL right- <+> "ON" <+> renderSQL on--{- | @left & fullOuterJoin right on@. First, an inner join is performed.- Then, for each row in @left@ that does not satisfy the @on@ condition with- any row in @right@, a joined row is added with null values in columns of @right@.- Also, for each row of @right@ that does not satisfy the join condition- with any row in @left@, a joined row with null values in the columns of @left@- is added.--}-fullOuterJoin- :: FromClause outer commons schemas params right- -- ^ right- -> Condition outer commons 'Ungrouped schemas params (Join left right)- -- ^ @on@ condition- -> FromClause outer commons schemas params left- -- ^ left- -> FromClause outer commons schemas params- (Join (NullifyFrom left) (NullifyFrom right))-fullOuterJoin right on left = UnsafeFromClause $- renderSQL left <+> "FULL OUTER JOIN" <+> renderSQL right- <+> "ON" <+> renderSQL on--{------------------------------------------Grouping------------------------------------------}---- | `By`s are used in `groupBy` to reference a list of columns which are then--- used to group together those rows in a table that have the same values--- in all the columns listed. @By \#col@ will reference an unambiguous--- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table--- qualified column @tab.col@.-data By- (from :: FromType)- (by :: (Symbol,Symbol)) where- By1- :: (HasUnique table from columns, Has column columns ty)- => Alias column- -> By from '(table, column)- By2- :: (Has table from columns, Has column columns ty)- => Alias table- -> Alias column- -> By from '(table, column)-deriving instance Show (By from by)-deriving instance Eq (By from by)-deriving instance Ord (By from by)-instance RenderSQL (By from by) where- renderSQL = \case- By1 column -> renderSQL column- By2 rel column -> renderSQL rel <> "." <> renderSQL column--instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))- => IsLabel col (By rels by) where fromLabel = By1 fromLabel-instance (HasUnique rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])- => IsLabel col (NP (By rels) bys) where fromLabel = By1 fromLabel :* Nil-instance (Has rel rels cols, Has col cols ty, by ~ '(rel, col))- => IsQualified rel col (By rels by) where (!) = By2-instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])- => IsQualified rel col (NP (By rels) bys) where- rel ! col = By2 rel col :* Nil---- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.--- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.--- @NoGroups@ is distinguised from @Group Nil@ since no aggregation can be--- done on @NoGroups@ while all output `Expression`s must be aggregated--- in @Group Nil@. In general, all output `Expression`s in the--- complement of @bys@ must be aggregated in @Group bys@.-data GroupByClause grp from where- NoGroups :: GroupByClause 'Ungrouped from- Group- :: SListI bys- => NP (By from) bys- -> GroupByClause ('Grouped bys) from---- | Renders a `GroupByClause`.-instance RenderSQL (GroupByClause grp from) where- renderSQL = \case- NoGroups -> ""- Group Nil -> ""- Group bys -> " GROUP BY" <+> renderCommaSeparated renderSQL bys---- | A `HavingClause` is used to eliminate groups that are not of interest.--- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`--- `TableExpression` must use `Having` whose conditions are combined with--- `.&&`.-data HavingClause outer commons grp schemas params from where- NoHaving :: HavingClause outer commons 'Ungrouped schemas params from- Having- :: [Condition outer commons ('Grouped bys) schemas params from]- -> HavingClause outer commons ('Grouped bys) schemas params from-deriving instance Show (HavingClause outer commons grp schemas params from)-deriving instance Eq (HavingClause outer commons grp schemas params from)-deriving instance Ord (HavingClause outer commons grp schemas params from)---- | Render a `HavingClause`.-instance RenderSQL (HavingClause outer commons grp schemas params from) where- renderSQL = \case- NoHaving -> ""- Having [] -> ""- Having conditions ->- " HAVING" <+> commaSeparated (renderSQL <$> conditions)---- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.-data CommonTableExpression statement- (schemas :: SchemasType)- (params :: [NullityType])- (commons0 :: FromType)- (commons1 :: FromType) where- CommonTableExpression- :: Aliased (statement commons schemas params) (cte ::: common)- -> CommonTableExpression statement schemas params commons (cte ::: common ': commons)-instance- ( KnownSymbol cte- , commons1 ~ (cte ::: common ': commons)- ) => Aliasable cte- (statement commons schemas params common)- (CommonTableExpression statement schemas params commons commons1) where- statement `as` cte = CommonTableExpression (statement `as` cte)-instance- ( KnownSymbol cte- , commons1 ~ (cte ::: common ': commons)- ) => Aliasable cte- (statement commons schemas params common)- (AlignedList (CommonTableExpression statement schemas params) commons commons1) where- statement `as` cte = single (statement `as` cte)--instance (forall c s p r. RenderSQL (statement c s p r)) => RenderSQL- (CommonTableExpression statement schemas params commons0 commons1) where- renderSQL (CommonTableExpression (statement `As` cte)) =- renderSQL cte <+> "AS" <+> parenthesized (renderSQL statement)---- | `with` provides a way to write auxiliary statements for use in a larger query.--- These statements, referred to as `CommonTableExpression`s, can be thought of as--- defining temporary tables that exist just for one query.-class With statement where- with- :: AlignedList (CommonTableExpression statement schemas params) commons0 commons1- -- ^ common table expressions- -> statement commons1 schemas params row- -- ^ larger query- -> statement commons0 schemas params row-instance With (Query outer) where- with Done query = query- with ctes query = UnsafeQuery $- "WITH" <+> renderSQL ctes <+> renderSQL query--{- |->>> import Data.Monoid (Sum (..))->>> import Data.Int (Int64)->>> :{- let- query :: Query_ schema () (Sum Int64)- query = withRecursive- ( values_ ((1 & astype int) `as` #n)- `unionAll`- select_ ((#n + 1) `as` #n)- (from (common #t) & where_ (#n .< 100)) `as` #t )- ( select_ (fromNull 0 (sum_ (All #n)) `as` #getSum) (from (common #t) & groupBy Nil))- in printSQL query-:}-WITH RECURSIVE "t" AS ((SELECT * FROM (VALUES ((1 :: int))) AS t ("n")) UNION ALL (SELECT ("n" + 1) AS "n" FROM "t" AS "t" WHERE ("n" < 100))) SELECT COALESCE(sum(ALL "n"), 0) AS "getSum" FROM "t" AS "t"--}-withRecursive- :: Aliased (Query outer (recursive ': commons) schemas params) recursive- -> Query outer (recursive ': commons) schemas params row- -> Query outer commons schemas params row-withRecursive (recursive `As` cte) query = UnsafeQuery $- "WITH RECURSIVE" <+> renderSQL cte- <+> "AS" <+> parenthesized (renderSQL recursive)- <+> renderSQL query
+ src/Squeal/PostgreSQL/Query/From.hs view
@@ -0,0 +1,110 @@+{-|+Module: Squeal.PostgreSQL.Query.From+Description: from clauses+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++from clauses+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.From+ ( -- * From Clause+ FromClause (..)+ , table+ , subquery+ , view+ , common+ ) where++import Control.DeepSeq+import Data.ByteString (ByteString)++import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{-----------------------------------------+FROM clauses+-----------------------------------------}++{- |+A `FromClause` can be a table name, or a derived table such+as a subquery, a @JOIN@ construct, or complex combinations of these.+-}+newtype FromClause+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType])+ (from :: FromType)+ = UnsafeFromClause { renderFromClause :: ByteString }+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (FromClause lat with db params from) where+ renderSQL = renderFromClause++-- | A real `table` is a table from the database.+table+ :: (Has sch db schema, Has tab schema ('Table table))+ => Aliased (QualifiedAlias sch) (alias ::: tab) -- ^ (renamable) table alias+ -> FromClause lat with db params '[alias ::: TableToRow table]+table (tab `As` alias) = UnsafeFromClause $+ renderSQL tab <+> "AS" <+> renderSQL alias++-- | `subquery` derives a table from a `Query`.+subquery+ :: Aliased (Query lat with db params) query+ -- ^ aliased `Query`+ -> FromClause lat with db params '[query]+subquery = UnsafeFromClause . renderAliased (parenthesized . renderSQL)++-- | `view` derives a table from a `View`.+view+ :: (Has sch db schema, Has vw schema ('View view))+ => Aliased (QualifiedAlias sch) (alias ::: vw) -- ^ (renamable) view alias+ -> FromClause lat with db params '[alias ::: view]+view (vw `As` alias) = UnsafeFromClause $+ renderSQL vw <+> "AS" <+> renderSQL alias++-- | `common` derives a table from a common table expression.+common+ :: Has cte with common+ => Aliased Alias (alias ::: cte) -- ^ (renamable) common table expression alias+ -> FromClause lat with db params '[alias ::: common]+common (cte `As` alias) = UnsafeFromClause $+ renderSQL cte <+> "AS" <+> renderSQL alias++instance Additional (FromClause lat with db params) where+ also right left = UnsafeFromClause $+ renderSQL left <> ", " <> renderSQL right
+ src/Squeal/PostgreSQL/Query/From/Join.hs view
@@ -0,0 +1,296 @@+{-|+Module: Squeal.PostgreSQL.Query.From.Join+Description: Squeal joins+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Squeal joins+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.From.Join+ ( -- * Join+ JoinItem (..)+ , cross, crossJoin, crossJoinLateral+ , inner, innerJoin, innerJoinLateral+ , leftOuter, leftOuterJoin, leftOuterJoinLateral+ , rightOuter, rightOuterJoin, rightOuterJoinLateral+ , fullOuter, fullOuterJoin, fullOuterJoinLateral+ ) where++import Generics.SOP hiding (from)++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Query.From+import Squeal.PostgreSQL.Query.From.Set+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{- |+A `JoinItem` is the right hand side of a `cross`,+`inner`, `leftOuter`, `rightOuter`, `fullOuter` join of+`FromClause`s.+-}+data JoinItem+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType])+ (left :: FromType)+ (right :: FromType) where+ Join+ :: FromClause lat with db params right+ -- ^ A standard `Squeal.PostgreSQL.Query.Join`.+ -- It is not allowed to reference columns provided+ -- by preceding `FromClause` items.+ -> JoinItem lat with db params left right+ JoinLateral+ :: Aliased (Query (Join lat left) with db params) query+ -- ^ Subqueries can be preceded by `JoinLateral`.+ -- This allows them to reference columns provided+ -- by preceding `FromClause` items.+ -- `subquery` is evaluated independently and so+ -- cannot cross-reference any other `FromClause` item.+ -> JoinItem lat with db params left '[query]+ JoinFunction+ :: SetFun db arg set+ -- ^ Set returning functions can be preceded by `JoinFunction`.+ -- This allows them to reference columns provided+ -- by preceding `FromClause` items.+ -> Expression 'Ungrouped lat with db params left arg+ -- ^ argument+ -> JoinItem lat with db params left '[set]+ JoinFunctionN+ :: SListI args+ => SetFunN db args set+ -- ^ Set returning multi-argument functions+ -- can be preceded by `JoinFunction`.+ -- This allows them to reference columns provided+ -- by preceding `FromClause` items.+ -> NP (Expression 'Ungrouped lat with db params left) args+ -- ^ arguments+ -> JoinItem lat with db params left '[set]+instance RenderSQL (JoinItem lat with db params left right) where+ renderSQL = \case+ Join tab -> "JOIN" <+> renderSQL tab+ JoinLateral qry -> "JOIN LATERAL" <+>+ renderAliased (parenthesized . renderSQL) qry+ JoinFunction fun x -> "JOIN" <+>+ renderSQL (fun (UnsafeExpression (renderSQL x)))+ JoinFunctionN fun xs -> "JOIN" <+>+ renderSQL (fun (SOP.hmap (UnsafeExpression . renderSQL) xs))++{- |+@left & cross (Join right)@. For every possible combination of rows from+@left@ and @right@ (i.e., a Cartesian product), the joined table will contain+a row consisting of all columns in @left@ followed by all columns in @right@.+If the tables have @n@ and @m@ rows respectively, the joined table will+have @n * m@ rows.+-}+cross+ :: JoinItem lat with db params left right -- ^ right+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left right)+cross item tab = UnsafeFromClause $+ renderSQL tab <+> "CROSS" <+> renderSQL item++{- |+@left & crossJoin right@. For every possible combination of rows from+@left@ and @right@ (i.e., a Cartesian product), the joined table will contain+a row consisting of all columns in @left@ followed by all columns in @right@.+If the tables have @n@ and @m@ rows respectively, the joined table will+have @n * m@ rows.+-}+crossJoin+ :: FromClause lat with db params right -- ^ right+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left right)+crossJoin = cross . Join++{- |+Like `crossJoin` with a `subquery` but allowed to reference columns provided+by preceding `FromClause` items.+-}+crossJoinLateral+ :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left '[query])+crossJoinLateral = cross . JoinLateral++{- | @left & inner (Join right) on@. The joined table is filtered by+the @on@ condition.+-}+inner+ :: JoinItem lat with db params left right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left right)+inner item on tab = UnsafeFromClause $+ renderSQL tab <+> "INNER" <+> renderSQL item <+> "ON" <+> renderSQL on++{- | @left & innerJoin right on@. The joined table is filtered by+the @on@ condition.+-}+innerJoin+ :: FromClause lat with db params right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left right)+innerJoin = inner . Join++{- |+Like `innerJoin` with a `subquery` but allowed to reference columns provided+by preceding `FromClause` items.+-}+innerJoinLateral+ :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery+ -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left '[query])+innerJoinLateral = inner . JoinLateral++{- | @left & leftOuter (Join right) on@. First, an inner join is performed.+Then, for each row in @left@ that does not satisfy the @on@ condition with+any row in @right@, a joined row is added with null values in columns of @right@.+Thus, the joined table always has at least one row for each row in @left@.+-}+leftOuter+ :: JoinItem lat with db params left right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left (NullifyFrom right))+leftOuter item on tab = UnsafeFromClause $+ renderSQL tab <+> "LEFT OUTER" <+> renderSQL item <+> "ON" <+> renderSQL on++{- | @left & leftOuterJoin right on@. First, an inner join is performed.+Then, for each row in @left@ that does not satisfy the @on@ condition with+any row in @right@, a joined row is added with null values in columns of @right@.+Thus, the joined table always has at least one row for each row in @left@.+-}+leftOuterJoin+ :: FromClause lat with db params right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left (NullifyFrom right))+leftOuterJoin = leftOuter . Join++{- |+Like `leftOuterJoin` with a `subquery` but allowed to reference columns provided+by preceding `FromClause` items.+-}+leftOuterJoinLateral+ :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery+ -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join left (NullifyFrom '[query]))+leftOuterJoinLateral = leftOuter . JoinLateral++{- | @left & rightOuter (Join right) on@. First, an inner join is performed.+Then, for each row in @right@ that does not satisfy the @on@ condition with+any row in @left@, a joined row is added with null values in columns of @left@.+This is the converse of a left join: the result table will always+have a row for each row in @right@.+-}+rightOuter+ :: JoinItem lat with db params left right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join (NullifyFrom left) right)+rightOuter item on tab = UnsafeFromClause $+ renderSQL tab <+> "RIGHT OUTER" <+> renderSQL item <+> "ON" <+> renderSQL on++{- | @left & rightOuterJoin right on@. First, an inner join is performed.+Then, for each row in @right@ that does not satisfy the @on@ condition with+any row in @left@, a joined row is added with null values in columns of @left@.+This is the converse of a left join: the result table will always+have a row for each row in @right@.+-}+rightOuterJoin+ :: FromClause lat with db params right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join (NullifyFrom left) right)+rightOuterJoin = rightOuter . Join++{- |+Like `rightOuterJoin` with a `subquery` but allowed to reference columns provided+by preceding `FromClause` items.+-}+rightOuterJoinLateral+ :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery+ -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (Join (NullifyFrom left) '[query])+rightOuterJoinLateral = rightOuter . JoinLateral++{- | @left & fullOuter (Join right) on@. First, an inner join is performed.+Then, for each row in @left@ that does not satisfy the @on@ condition with+any row in @right@, a joined row is added with null values in columns of @right@.+Also, for each row of @right@ that does not satisfy the join condition+with any row in @left@, a joined row with null values in the columns of @left@+is added.+-}+fullOuter+ :: JoinItem lat with db params left right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (NullifyFrom (Join left right))+fullOuter item on tab = UnsafeFromClause $+ renderSQL tab <+> "FULL OUTER" <+> renderSQL item <+> "ON" <+> renderSQL on++{- | @left & fullOuterJoin right on@. First, an inner join is performed.+Then, for each row in @left@ that does not satisfy the @on@ condition with+any row in @right@, a joined row is added with null values in columns of @right@.+Also, for each row of @right@ that does not satisfy the join condition+with any row in @left@, a joined row with null values in the columns of @left@+is added.+-}+fullOuterJoin+ :: FromClause lat with db params right -- ^ right+ -> Condition 'Ungrouped lat with db params (Join left right) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (NullifyFrom (Join left right))+fullOuterJoin = fullOuter . Join++{- |+Like `fullOuterJoin` with a `subquery` but allowed to reference columns provided+by preceding `FromClause` items.+-}+fullOuterJoinLateral+ :: Aliased (Query (Join lat left) with db params) query -- ^ right subquery+ -> Condition 'Ungrouped lat with db params (Join left '[query]) -- ^ @ON@ condition+ -> FromClause lat with db params left -- ^ left+ -> FromClause lat with db params (NullifyFrom (Join left '[query]))+fullOuterJoinLateral = fullOuter . JoinLateral
+ src/Squeal/PostgreSQL/Query/From/Set.hs view
@@ -0,0 +1,204 @@+{-|+Module: Squeal.PostgreSQL.Query.From.Set+Description: set returning functions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++set returning functions+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.From.Set+ ( -- * Set Functions+ type (-|->)+ , type (--|->)+ , SetFun+ , SetFunN+ , generateSeries+ , generateSeriesStep+ , generateSeriesTimestamp+ , unsafeSetFunction+ , setFunction+ , unsafeSetFunctionN+ , setFunctionN+ ) where++import Data.ByteString (ByteString)+import Generics.SOP hiding (from)+import GHC.TypeLits++import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Query.From+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema++{- |+A @RankNType@ for set returning functions with 1 argument.+-}+type (-|->) arg set = forall db. SetFun db arg set++{- |+A @RankNType@ for set returning functions with multiple argument.+-}+type (--|->) arg set = forall db. SetFunN db arg set+ -- ^ output++{- |+Like `-|->` but depends on the schemas of the database+-}+type SetFun db arg row+ = forall lat with params+ . Expression 'Ungrouped lat with db params '[] arg+ -- ^ input+ -> FromClause lat with db params '[row]+ -- ^ output++{- |+Like `--|->` but depends on the schemas of the database+-}+type SetFunN db args set+ = forall lat with params+ . NP (Expression 'Ungrouped lat with db params '[]) args+ -- ^ input+ -> FromClause lat with db params '[set]+ -- ^ output++-- $setup+-- >>> import Squeal.PostgreSQL++-- | Escape hatch for a set returning function of a single variable+unsafeSetFunction+ :: forall fun ty row. KnownSymbol fun+ => ByteString+ -> ty -|-> (fun ::: row) -- ^ set returning function+unsafeSetFunction fun x = UnsafeFromClause $+ fun <> parenthesized (renderSQL x)++{- | Call a user defined set returning function of a single variable++>>> type Fn = '[ 'Null 'PGbool] :=> 'ReturnsTable '["ret" ::: 'NotNull 'PGnumeric]+>>> type Schema = '["fn" ::: 'Function Fn]+>>> :{+let+ fn :: SetFun (Public Schema) ('Null 'PGbool) ("fn" ::: '["ret" ::: 'NotNull 'PGnumeric])+ fn = setFunction #fn+in+ printSQL (fn true)+:}+"fn"(TRUE)+-}+setFunction+ :: ( Has sch db schema+ , Has fun schema ('Function ('[ty] :=> 'ReturnsTable row)) )+ => QualifiedAlias sch fun -- ^ function alias+ -> SetFun db ty (fun ::: row)+setFunction fun = unsafeSetFunction (renderSQL fun)++{- | Escape hatch for a multivariable set returning function-}+unsafeSetFunctionN+ :: forall fun tys row. (SOP.SListI tys, KnownSymbol fun)+ => ByteString+ -> tys --|-> (fun ::: row) -- ^ set returning function+unsafeSetFunctionN fun xs = UnsafeFromClause $+ fun <> parenthesized (renderCommaSeparated renderSQL xs)++{- | Call a user defined multivariable set returning function++>>> type Fn = '[ 'Null 'PGbool, 'Null 'PGtext] :=> 'ReturnsTable '["ret" ::: 'NotNull 'PGnumeric]+>>> type Schema = '["fn" ::: 'Function Fn]+>>> :{+let+ fn :: SetFunN (Public Schema)+ '[ 'Null 'PGbool, 'Null 'PGtext]+ ("fn" ::: '["ret" ::: 'NotNull 'PGnumeric])+ fn = setFunctionN #fn+in+ printSQL (fn (true *: "hi"))+:}+"fn"(TRUE, (E'hi' :: text))+-}+setFunctionN+ :: ( Has sch db schema+ , Has fun schema ('Function (tys :=> 'ReturnsTable row))+ , SOP.SListI tys )+ => QualifiedAlias sch fun -- ^ function alias+ -> SetFunN db tys (fun ::: row)+setFunctionN fun = unsafeSetFunctionN (renderSQL fun)++{- | @generateSeries (start :* stop)@++Generate a series of values,+from @start@ to @stop@ with a step size of one++>>> printSQL (generateSeries @'PGint4 (1 *: 10))+generate_series((1 :: int4), (10 :: int4))+-}+generateSeries+ :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric]+ => '[ null ty, null ty] --|->+ ("generate_series" ::: '["generate_series" ::: null ty])+ -- ^ set returning function+generateSeries = unsafeSetFunctionN "generate_series"++{- | @generateSeriesStep (start :* stop *: step)@++Generate a series of values,+from @start@ to @stop@ with a step size of @step@++>>> printSQL (generateSeriesStep @'PGint8 (2 :* 100 *: 2))+generate_series((2 :: int8), (100 :: int8), (2 :: int8))+-}+generateSeriesStep+ :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric]+ => '[null ty, null ty, null ty] --|->+ ("generate_series" ::: '["generate_series" ::: null ty])+ -- ^ set returning function+generateSeriesStep = unsafeSetFunctionN "generate_series"++{- | @generateSeriesTimestamp (start :* stop *: step)@++Generate a series of timestamps,+from @start@ to @stop@ with a step size of @step@++>>> :{+let+ start = now+ stop = now !+ interval_ 10 Years+ step = interval_ 1 Months+in printSQL (generateSeriesTimestamp (start :* stop *: step))+:}+generate_series(now(), (now() + (INTERVAL '10.000 years')), (INTERVAL '1.000 months'))+-}+generateSeriesTimestamp+ :: ty `In` '[ 'PGtimestamp, 'PGtimestamptz]+ => '[null ty, null ty, null 'PGinterval] --|->+ ("generate_series" ::: '["generate_series" ::: null ty])+ -- ^ set returning function+generateSeriesTimestamp = unsafeSetFunctionN "generate_series"
+ src/Squeal/PostgreSQL/Query/Select.hs view
@@ -0,0 +1,252 @@+{-|+Module: Squeal.PostgreSQL.Query.Select+Description: select statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++select statements+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.Select+ ( -- ** Select+ select+ , select_+ , selectDistinct+ , selectDistinct_+ , selectDistinctOn+ , selectDistinctOn_+ , Selection (..)+ ) where++import Data.ByteString (ByteString)+import Data.String+import Generics.SOP hiding (from)+import GHC.TypeLits++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Expression.Sort+import Squeal.PostgreSQL.Expression.Window+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Query.Table+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{-----------------------------------------+SELECT queries+-----------------------------------------}++{- | The simplest kinds of `Selection` are `Star` and `DotStar` which+emits all columns that a `TableExpression` produces. A select `List`+is a list of `Expression`s. A `Selection` could be a list of+`WindowFunction`s `Over` `WindowDefinition`. `Additional` `Selection`s can+be selected with `Also`.+-}+data Selection grp lat with db params from row where+ Star+ :: HasUnique tab from row+ => Selection 'Ungrouped lat with db params from row+ -- ^ `HasUnique` table in the `Squeal.PostgreSQL.Query.From.FromClause`+ DotStar+ :: Has tab from row+ => Alias tab+ -- ^ `Has` table with `Alias`+ -> Selection 'Ungrouped lat with db params from row+ List+ :: SListI row+ => NP (Aliased (Expression grp lat with db params from)) row+ -- ^ `NP` list of `Aliased` `Expression`s+ -> Selection grp lat with db params from row+ Over+ :: SListI row+ => NP (Aliased (WindowFunction grp lat with db params from)) row+ -- ^ `NP` list of `Aliased` `WindowFunction`s+ -> WindowDefinition grp lat with db params from+ -> Selection grp lat with db params from row+ Also+ :: Selection grp lat with db params from right+ -- ^ `Additional` `Selection`+ -> Selection grp lat with db params from left+ -> Selection grp lat with db params from (Join left right)+instance Additional (Selection grp lat with db params from) where+ also = Also+instance (KnownSymbol col, row ~ '[col ::: ty])+ => Aliasable col+ (Expression grp lat with db params from ty)+ (Selection grp lat with db params from row) where+ expr `as` col = List (expr `as` col)+instance (Has tab (Join lat from) row0, Has col row0 ty, row1 ~ '[col ::: ty])+ => IsQualified tab col+ (Selection 'Ungrouped lat with db params from row1) where+ tab ! col = tab ! col `as` col+instance+ ( Has tab (Join lat from) row0+ , Has col row0 ty+ , row1 ~ '[col ::: ty]+ , GroupedBy tab col bys )+ => IsQualified tab col+ (Selection ('Grouped bys) lat with db params from row1) where+ tab ! col = tab ! col `as` col+instance (HasUnique tab (Join lat from) row0, Has col row0 ty, row1 ~ '[col ::: ty])+ => IsLabel col+ (Selection 'Ungrouped lat with db params from row1) where+ fromLabel = fromLabel @col `as` Alias+instance+ ( HasUnique tab (Join lat from) row0+ , Has col row0 ty+ , row1 ~ '[col ::: ty]+ , GroupedBy tab col bys )+ => IsLabel col+ (Selection ('Grouped bys) lat with db params from row1) where+ fromLabel = fromLabel @col `as` Alias++instance RenderSQL (Selection grp lat with db params from row) where+ renderSQL = \case+ List list -> renderCommaSeparated (renderAliased renderSQL) list+ Star -> "*"+ DotStar tab -> renderSQL tab <> ".*"+ Also right left -> renderSQL left <> ", " <> renderSQL right+ Over winFns winDef ->+ let+ renderOver+ :: Aliased (WindowFunction grp lat with db params from) field+ -> ByteString+ renderOver (winFn `As` col) = renderSQL winFn+ <+> "OVER" <+> parenthesized (renderSQL winDef)+ <+> "AS" <+> renderSQL col+ in+ renderCommaSeparated renderOver winFns++instance IsString+ (Selection grp lat with db params from '["fromOnly" ::: 'NotNull 'PGtext]) where+ fromString str = fromString str `as` Alias++-- | the `TableExpression` in the `select` command constructs an intermediate+-- virtual table by possibly combining tables, views, eliminating rows,+-- grouping, etc. This table is finally passed on to processing by+-- the select list. The `Selection` determines which columns of+-- the intermediate table are actually output.+select+ :: (SListI row, row ~ (x ': xs))+ => Selection grp lat with db params from row+ -- ^ selection+ -> TableExpression grp lat with db params from+ -- ^ intermediate virtual table+ -> Query lat with db params row+select selection tabexpr = UnsafeQuery $+ "SELECT"+ <+> renderSQL selection+ <+> renderSQL tabexpr++-- | Like `select` but takes an `NP` list of `Expression`s instead+-- of a general `Selection`.+select_+ :: (SListI row, row ~ (x ': xs))+ => NP (Aliased (Expression grp lat with db params from)) row+ -- ^ select list+ -> TableExpression grp lat with db params from+ -- ^ intermediate virtual table+ -> Query lat with db params row+select_ = select . List++-- | After the select list has been processed, the result table can+-- be subject to the elimination of duplicate rows using `selectDistinct`.+selectDistinct+ :: (SListI columns, columns ~ (col ': cols))+ => Selection grp lat with db params from columns+ -- ^ selection+ -> TableExpression grp lat with db params from+ -- ^ intermediate virtual table+ -> Query lat with db params columns+selectDistinct selection tabexpr = UnsafeQuery $+ "SELECT DISTINCT"+ <+> renderSQL selection+ <+> renderSQL tabexpr++-- | Like `selectDistinct` but takes an `NP` list of `Expression`s instead+-- of a general `Selection`.+selectDistinct_+ :: (SListI columns, columns ~ (col ': cols))+ => NP (Aliased (Expression grp lat with db params from)) columns+ -- ^ select list+ -> TableExpression grp lat with db params from+ -- ^ intermediate virtual table+ -> Query lat with db params columns+selectDistinct_ = selectDistinct . List++{-|+`selectDistinctOn` keeps only the first row of each set of rows where+the given expressions evaluate to equal. The DISTINCT ON expressions are+interpreted using the same rules as for ORDER BY. ORDER BY is used to+ensure that the desired row appears first.++The DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s).+The ORDER BY clause will normally contain additional expression(s) that+determine the desired precedence of rows within each DISTINCT ON group.++In order to guarantee they match and reduce redundancy, this function+will prepend the The DISTINCT ON expressions to the ORDER BY clause.+-}+selectDistinctOn+ :: (SListI columns, columns ~ (col ': cols))+ => [SortExpression grp lat with db params from]+ -- ^ DISTINCT ON expression(s) and prepended to ORDER BY clause+ -> Selection grp lat with db params from columns+ -- ^ selection+ -> TableExpression grp lat with db params from+ -- ^ intermediate virtual table+ -> Query lat with db params columns+selectDistinctOn distincts selection tab = UnsafeQuery $+ "SELECT DISTINCT ON"+ <+> parenthesized (commaSeparated (renderDistinctOn <$> distincts))+ <+> renderSQL selection+ <+> renderSQL (tab {orderByClause = distincts <> orderByClause tab})+ where+ renderDistinctOn = \case+ Asc expression -> renderSQL expression+ Desc expression -> renderSQL expression+ AscNullsFirst expression -> renderSQL expression+ DescNullsFirst expression -> renderSQL expression+ AscNullsLast expression -> renderSQL expression+ DescNullsLast expression -> renderSQL expression++-- | Like `selectDistinctOn` but takes an `NP` list of `Expression`s instead+-- of a general `Selection`.+selectDistinctOn_+ :: (SListI columns, columns ~ (col ': cols))+ => [SortExpression grp lat with db params from]+ -- ^ distinct on and return the first row in ordering+ -> NP (Aliased (Expression grp lat with db params from)) columns+ -- ^ selection+ -> TableExpression grp lat with db params from+ -- ^ intermediate virtual table+ -> Query lat with db params columns+selectDistinctOn_ distincts = selectDistinctOn distincts . List
+ src/Squeal/PostgreSQL/Query/Table.hs view
@@ -0,0 +1,289 @@+{-|+Module: Squeal.PostgreSQL.Query.Table+Description: intermediate table expressions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++intermediate table expressions+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.Table+ ( -- * Table Expression+ TableExpression (..)+ , from+ , where_+ , groupBy+ , having+ , limit+ , offset+ -- * Grouping+ , By (..)+ , GroupByClause (..)+ , HavingClause (..)+ ) where++import Control.DeepSeq+import Data.ByteString (ByteString)+import Data.String+import Data.Word+import Generics.SOP hiding (from)+import GHC.TypeLits++import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression.Logic+import Squeal.PostgreSQL.Expression.Sort+import Squeal.PostgreSQL.Query.From+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++{-----------------------------------------+Table Expressions+-----------------------------------------}++-- | A `TableExpression` computes a table. The table expression contains+-- a `fromClause` that is optionally followed by a `whereClause`,+-- `groupByClause`, `havingClause`, `orderByClause`, `limitClause`+-- and `offsetClause`s. Trivial table expressions simply refer+-- to a table on disk, a so-called base table, but more complex expressions+-- can be used to modify or combine base tables in various ways.+data TableExpression+ (grp :: Grouping)+ (lat :: FromType)+ (with :: FromType)+ (db :: SchemasType)+ (params :: [NullType])+ (from :: FromType)+ = TableExpression+ { fromClause :: FromClause lat with db params from+ -- ^ A table reference that can be a table name, or a derived table such+ -- as a subquery, a @JOIN@ construct, or complex combinations of these.+ , whereClause :: [Condition 'Ungrouped lat with db params from]+ -- ^ optional search coditions, combined with `.&&`. After the processing+ -- of the `fromClause` is done, each row of the derived virtual table+ -- is checked against the search condition. If the result of the+ -- condition is true, the row is kept in the output table,+ -- otherwise it is discarded. The search condition typically references+ -- at least one column of the table generated in the `fromClause`;+ -- this is not required, but otherwise the WHERE clause will+ -- be fairly useless.+ , groupByClause :: GroupByClause grp from+ -- ^ The `groupByClause` is used to group together those rows in a table+ -- that have the same values in all the columns listed. The order in which+ -- the columns are listed does not matter. The effect is to combine each+ -- set of rows having common values into one group row that represents all+ -- rows in the group. This is done to eliminate redundancy in the output+ -- and/or compute aggregates that apply to these groups.+ , havingClause :: HavingClause grp lat with db params from+ -- ^ If a table has been grouped using `groupBy`, but only certain groups+ -- are of interest, the `havingClause` can be used, much like a+ -- `whereClause`, to eliminate groups from the result. Expressions in the+ -- `havingClause` can refer both to grouped expressions and to ungrouped+ -- expressions (which necessarily involve an aggregate function).+ , orderByClause :: [SortExpression grp lat with db params from]+ -- ^ The `orderByClause` is for optional sorting. When more than one+ -- `SortExpression` is specified, the later (right) values are used to sort+ -- rows that are equal according to the earlier (left) values.+ , limitClause :: [Word64]+ -- ^ The `limitClause` is combined with `min` to give a limit count+ -- if nonempty. If a limit count is given, no more than that many rows+ -- will be returned (but possibly fewer, if the query itself yields+ -- fewer rows).+ , offsetClause :: [Word64]+ -- ^ The `offsetClause` is combined with `Prelude.+` to give an offset count+ -- if nonempty. The offset count says to skip that many rows before+ -- beginning to return rows. The rows are skipped before the limit count+ -- is applied.+ } deriving (GHC.Generic)++-- | Render a `TableExpression`+instance RenderSQL (TableExpression grp lat with db params from) where+ renderSQL+ (TableExpression frm' whs' grps' hvs' srts' lims' offs') = mconcat+ [ "FROM ", renderSQL frm'+ , renderWheres whs'+ , renderSQL grps'+ , renderSQL hvs'+ , renderSQL srts'+ , renderLimits lims'+ , renderOffsets offs' ]+ where+ renderWheres = \case+ [] -> ""+ wh:whs -> " WHERE" <+> renderSQL (foldr (.&&) wh whs)+ renderLimits = \case+ [] -> ""+ lims -> " LIMIT" <+> fromString (show (minimum lims))+ renderOffsets = \case+ [] -> ""+ offs -> " OFFSET" <+> fromString (show (sum offs))++-- | A `from` generates a `TableExpression` from a table reference that can be+-- a table name, or a derived table such as a subquery, a JOIN construct,+-- or complex combinations of these. A `from` may be transformed by `where_`,+-- `groupBy`, `having`, `orderBy`, `limit` and `offset`,+-- using the `Data.Function.&` operator+-- to match the left-to-right sequencing of their placement in SQL.+from+ :: FromClause lat with db params from -- ^ table reference+ -> TableExpression 'Ungrouped lat with db params from+from tab = TableExpression tab [] noGroups NoHaving [] [] []++-- | A `where_` is an endomorphism of `TableExpression`s which adds a+-- search condition to the `whereClause`.+where_+ :: Condition 'Ungrouped lat with db params from -- ^ filtering condition+ -> TableExpression grp lat with db params from+ -> TableExpression grp lat with db params from+where_ wh rels = rels {whereClause = wh : whereClause rels}++-- | A `groupBy` is a transformation of `TableExpression`s which switches+-- its `Grouping` from `Ungrouped` to `Grouped`. Use @groupBy Nil@ to perform+-- a "grand total" aggregation query.+groupBy+ :: SListI bys+ => NP (By from) bys -- ^ grouped columns+ -> TableExpression 'Ungrouped lat with db params from+ -> TableExpression ('Grouped bys) lat with db params from+groupBy bys rels = TableExpression+ { fromClause = fromClause rels+ , whereClause = whereClause rels+ , groupByClause = group bys+ , havingClause = Having []+ , orderByClause = []+ , limitClause = limitClause rels+ , offsetClause = offsetClause rels+ }++-- | A `having` is an endomorphism of `TableExpression`s which adds a+-- search condition to the `havingClause`.+having+ :: Condition ('Grouped bys) lat with db params from -- ^ having condition+ -> TableExpression ('Grouped bys) lat with db params from+ -> TableExpression ('Grouped bys) lat with db params from+having hv rels = rels+ { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }++instance OrderBy (TableExpression grp) grp where+ orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}++-- | A `limit` is an endomorphism of `TableExpression`s which adds to the+-- `limitClause`.+limit+ :: Word64 -- ^ limit parameter+ -> TableExpression grp lat with db params from+ -> TableExpression grp lat with db params from+limit lim rels = rels {limitClause = lim : limitClause rels}++-- | An `offset` is an endomorphism of `TableExpression`s which adds to the+-- `offsetClause`.+offset+ :: Word64 -- ^ offset parameter+ -> TableExpression grp lat with db params from+ -> TableExpression grp lat with db params from+offset off rels = rels {offsetClause = off : offsetClause rels}++{-----------------------------------------+Grouping+-----------------------------------------}++-- | `By`s are used in `groupBy` to reference a list of columns which are then+-- used to group together those rows in a table that have the same values+-- in all the columns listed. @By \#col@ will reference an unambiguous+-- column @col@; otherwise @By2 (\#tab \! \#col)@ will reference a table+-- qualified column @tab.col@.+data By+ (from :: FromType)+ (by :: (Symbol,Symbol)) where+ By1+ :: (HasUnique table from columns, Has column columns ty)+ => Alias column+ -> By from '(table, column)+ By2+ :: (Has table from columns, Has column columns ty)+ => Alias table+ -> Alias column+ -> By from '(table, column)+deriving instance Show (By from by)+deriving instance Eq (By from by)+deriving instance Ord (By from by)+instance RenderSQL (By from by) where+ renderSQL = \case+ By1 column -> renderSQL column+ By2 rel column -> renderSQL rel <> "." <> renderSQL column++instance (HasUnique rel rels cols, Has col cols ty, by ~ '(rel, col))+ => IsLabel col (By rels by) where fromLabel = By1 fromLabel+instance (HasUnique rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])+ => IsLabel col (NP (By rels) bys) where fromLabel = By1 fromLabel :* Nil+instance (Has rel rels cols, Has col cols ty, by ~ '(rel, col))+ => IsQualified rel col (By rels by) where (!) = By2+instance (Has rel rels cols, Has col cols ty, bys ~ '[ '(rel, col)])+ => IsQualified rel col (NP (By rels) bys) where+ rel ! col = By2 rel col :* Nil++-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.+newtype GroupByClause grp from = UnsafeGroupByClause+ { renderGroupByClause :: ByteString }+ deriving stock (GHC.Generic,Show,Eq,Ord)+ deriving newtype (NFData)+instance RenderSQL (GroupByClause grp from) where+ renderSQL = renderGroupByClause+noGroups :: GroupByClause 'Ungrouped from+noGroups = UnsafeGroupByClause ""+group+ :: SListI bys+ => NP (By from) bys+ -> GroupByClause ('Grouped bys) from+group bys = UnsafeGroupByClause $ case bys of+ Nil -> ""+ _ -> " GROUP BY" <+> renderCommaSeparated renderSQL bys++-- | A `HavingClause` is used to eliminate groups that are not of interest.+-- An `Ungrouped` `TableExpression` may only use `NoHaving` while a `Grouped`+-- `TableExpression` must use `Having` whose conditions are combined with+-- `.&&`.+data HavingClause grp lat with db params from where+ NoHaving :: HavingClause 'Ungrouped lat with db params from+ Having+ :: [Condition ('Grouped bys) lat with db params from]+ -> HavingClause ('Grouped bys) lat with db params from+deriving instance Show (HavingClause grp lat with db params from)+deriving instance Eq (HavingClause grp lat with db params from)+deriving instance Ord (HavingClause grp lat with db params from)++-- | Render a `HavingClause`.+instance RenderSQL (HavingClause grp lat with db params from) where+ renderSQL = \case+ NoHaving -> ""+ Having [] -> ""+ Having conditions ->+ " HAVING" <+> commaSeparated (renderSQL <$> conditions)
+ src/Squeal/PostgreSQL/Query/Values.hs view
@@ -0,0 +1,88 @@+{-|+Module: Squeal.PostgreSQL.Query.Values+Description: values statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++values statements+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.Values+ ( -- ** Values+ values+ , values_+ ) where++import Data.ByteString (ByteString)+import Generics.SOP hiding (from)++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Expression+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Render++-- $setup+-- >>> import Squeal.PostgreSQL++-- | `values` computes a row value or set of row values+-- specified by value expressions. It is most commonly used+-- to generate a “constant table” within a larger command,+-- but it can be used on its own.+--+-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]+-- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query lat with db '[] Row+-- >>> printSQL query+-- SELECT * FROM (VALUES ((1 :: int4), (E'one' :: text))) AS t ("a", "b")+values+ :: SListI cols+ => NP (Aliased (Expression 'Ungrouped lat with db params '[] )) cols+ -> [NP (Aliased (Expression 'Ungrouped lat with db params '[] )) cols]+ -- ^ When more than one row is specified, all the rows must+ -- must have the same number of elements+ -> Query lat with db params cols+values rw rws = UnsafeQuery $ "SELECT * FROM"+ <+> parenthesized (+ "VALUES"+ <+> commaSeparated+ ( parenthesized+ . renderCommaSeparated renderValuePart <$> rw:rws )+ ) <+> "AS t"+ <+> parenthesized (renderCommaSeparated renderAliasPart rw)+ where+ renderAliasPart, renderValuePart+ :: Aliased (Expression 'Ungrouped lat with db params '[] ) ty -> ByteString+ renderAliasPart (_ `As` name) = renderSQL name+ renderValuePart (value `As` _) = renderSQL value++-- | `values_` computes a row value or set of row values+-- specified by value expressions.+values_+ :: SListI cols+ => NP (Aliased (Expression 'Ungrouped lat with db params '[] )) cols+ -- ^ one row of values+ -> Query lat with db params cols+values_ rw = values rw []
+ src/Squeal/PostgreSQL/Query/With.hs view
@@ -0,0 +1,123 @@+{-|+Module: Squeal.PostgreSQL.Query.With+Description: with statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++with statements+-}++{-# LANGUAGE+ ConstraintKinds+ , DeriveGeneric+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , GADTs+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , QuantifiedConstraints+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , RankNTypes+ , UndecidableInstances+ #-}++module Squeal.PostgreSQL.Query.With+ ( -- ** With+ With (..)+ , CommonTableExpression (..)+ , withRecursive+ ) where++import Data.Quiver.Functor+import GHC.TypeLits++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++-- | `with` provides a way to write auxiliary statements for use in a larger query.+-- These statements, referred to as `CommonTableExpression`s, can be thought of as+-- defining temporary tables that exist just for one query.+class With statement where+ with+ :: Path (CommonTableExpression statement db params) with0 with1+ -- ^ common table expressions+ -> statement with1 db params row+ -- ^ larger query+ -> statement with0 db params row+instance With (Query lat) where+ with Done query = query+ with ctes query = UnsafeQuery $+ "WITH" <+> commaSeparated (qtoList renderSQL ctes) <+> renderSQL query++{- |+>>> import Data.Monoid (Sum (..))+>>> import Data.Int (Int64)+>>> :{+ let+ query :: Query_ schema () (Sum Int64)+ query = withRecursive+ ( values_ ((1 & astype int) `as` #n)+ `unionAll`+ select_ ((#n + 1) `as` #n)+ (from (common #t) & where_ (#n .< 100)) `as` #t )+ ( select_ (fromNull 0 (sum_ (All #n)) `as` #getSum) (from (common #t) & groupBy Nil))+ in printSQL query+:}+WITH RECURSIVE "t" AS ((SELECT * FROM (VALUES (((1 :: int4) :: int))) AS t ("n")) UNION ALL (SELECT ("n" + (1 :: int4)) AS "n" FROM "t" AS "t" WHERE ("n" < (100 :: int4)))) SELECT COALESCE(sum(ALL "n"), (0 :: int8)) AS "getSum" FROM "t" AS "t"+-}+withRecursive+ :: Aliased (Query lat (recursive ': with) db params) recursive+ -- ^ recursive query+ -> Query lat (recursive ': with) db params row+ -- ^ larger query+ -> Query lat with db params row+withRecursive (recursive `As` cte) query = UnsafeQuery $+ "WITH RECURSIVE" <+> renderSQL cte+ <+> "AS" <+> parenthesized (renderSQL recursive)+ <+> renderSQL query++-- | A `CommonTableExpression` is an auxiliary statement in a `with` clause.+data CommonTableExpression statement+ (db :: SchemasType)+ (params :: [NullType])+ (with0 :: FromType)+ (with1 :: FromType) where+ CommonTableExpression+ :: Aliased (statement with db params) (cte ::: common)+ -- ^ aliased statement+ -> CommonTableExpression statement db params with (cte ::: common ': with)+instance+ ( KnownSymbol cte+ , with1 ~ (cte ::: common ': with)+ ) => Aliasable cte+ (statement with db params common)+ (CommonTableExpression statement db params with with1) where+ statement `as` cte = CommonTableExpression (statement `as` cte)+instance+ ( KnownSymbol cte+ , with1 ~ (cte ::: common ': with)+ ) => Aliasable cte+ (statement with db params common)+ (Path (CommonTableExpression statement db params) with with1) where+ statement `as` cte = qsingle (statement `as` cte)++instance (forall c s p r. RenderSQL (statement c s p r)) => RenderSQL+ (CommonTableExpression statement db params with0 with1) where+ renderSQL (CommonTableExpression (statement `As` cte)) =+ renderSQL cte <+> "AS" <+> parenthesized (renderSQL statement)
src/Squeal/PostgreSQL/Render.hs view
@@ -1,11 +1,11 @@ {-| Module: Squeal.PostgreSQL.Render-Description: Rendering helper functions-Copyright: (c) Eitan Chatav, 2017+Description: render functions+Copyright: (c) Eitan Chatav, 2019 Maintainer: eitan@morphism.tech Stability: experimental -Rendering helper functions.+render functions -} {-# LANGUAGE@@ -33,6 +33,8 @@ , doubleQuoted , singleQuotedText , singleQuotedUtf8+ , escapeQuotedString+ , escapeQuotedText , renderCommaSeparated , renderCommaSeparatedConstraint , renderCommaSeparatedMaybe@@ -43,7 +45,6 @@ import Control.Monad.IO.Class (MonadIO (..)) import Data.ByteString (ByteString) import Data.Maybe (catMaybes)-import Data.Monoid ((<>)) import Data.Text (Text) import Generics.SOP import GHC.Exts@@ -84,6 +85,15 @@ singleQuotedUtf8 :: ByteString -> ByteString singleQuotedUtf8 = singleQuotedText . Text.decodeUtf8 +-- | Escape quote a string.+escapeQuotedString :: String -> ByteString+escapeQuotedString x = "E\'" <> Text.encodeUtf8 (fromString (escape =<< x)) <> "\'"++-- | Escape quote a string.+escapeQuotedText :: Text -> ByteString+escapeQuotedText x =+ "E\'" <> Text.encodeUtf8 (Text.concatMap (fromString . escape) x) <> "\'"+ -- | Comma separate the renderings of a heterogeneous list. renderCommaSeparated :: SListI xs@@ -134,7 +144,7 @@ -- | `escape` a character to prevent injection escape :: Char -> String escape = \case- '\NUL' -> "\\0"+ '\NUL' -> "" '\'' -> "''" '"' -> "\\\"" '\b' -> "\\b"
− src/Squeal/PostgreSQL/Schema.hs
@@ -1,449 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Schema-Description: Embedding of PostgreSQL type and alias system-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--`Squeal.PostgreSQL.Schema` provides a type-level DSL for kinds of Postgres types,-tables, schema, constraints, aliases, enumerated labels, and groupings.-It also defines useful type families to operate on these. Finally,-it defines an embedding of Haskell types into Postgres types.--}-{-# LANGUAGE- AllowAmbiguousTypes- , ConstraintKinds- , DeriveAnyClass- , DeriveGeneric- , FlexibleContexts- , FlexibleInstances- , FunctionalDependencies- , GADTs- , LambdaCase- , OverloadedStrings- , QuantifiedConstraints- , RankNTypes- , ScopedTypeVariables- , StandaloneDeriving- , TypeApplications- , TypeFamilyDependencies- , TypeInType- , TypeOperators- , UndecidableInstances- , UndecidableSuperClasses-#-}--module Squeal.PostgreSQL.Schema- ( -- * Postgres Types- PGType (..)- , NullityType (..)- , RowType- , FromType- -- * Schema Types- , ColumnType- , ColumnsType- , TableType- , SchemumType (..)- , SchemaType- , SchemasType- , Public- -- * Constraints- , (:=>)- , ColumnConstraint (..)- , TableConstraint (..)- , TableConstraints- , Uniquely- -- * Enumerated Labels- , IsPGlabel (..)- , PGlabel (..)- -- * Data Definitions- , Create- , Drop- , Alter- , Rename- , ConstraintInvolves- , DropIfConstraintsInvolve- , IsNotElem- , AllUnique- -- * Type Classifications- , PGNum- , PGIntegral- , PGFloating- , PGTypeOf- , PGJsonType- , PGJsonKey- , SamePGType- , AllNotNull- , NotAllNull- -- * Nullifications- , NullifyType- , NullifyRow- , NullifyFrom- -- * Table Conversions- , TableToColumns- , ColumnsToRow- , TableToRow- ) where--import Control.Category-import Data.Kind-import Data.Monoid hiding (All)-import Data.Type.Bool-import Generics.SOP-import GHC.TypeLits-import Prelude hiding (id, (.))--import Squeal.PostgreSQL.Alias-import Squeal.PostgreSQL.List-import Squeal.PostgreSQL.Render---- $setup--- >>> import Squeal.PostgreSQL---- | `PGType` is the promoted datakind of PostgreSQL types.------ >>> :kind 'PGbool--- 'PGbool :: PGType-data PGType- = PGbool -- ^ logical Boolean (true/false)- | PGint2 -- ^ signed two-byte integer- | PGint4 -- ^ signed four-byte integer- | PGint8 -- ^ signed eight-byte integer- | PGnumeric -- ^ arbitrary precision numeric type- | PGfloat4 -- ^ single precision floating-point number (4 bytes)- | PGfloat8 -- ^ double precision floating-point number (8 bytes)- | PGmoney -- ^ currency amount- | PGchar Nat -- ^ fixed-length character string- | PGvarchar Nat -- ^ variable-length character string- | PGtext -- ^ variable-length character string- | PGbytea -- ^ binary data ("byte array")- | PGtimestamp -- ^ date and time (no time zone)- | PGtimestamptz -- ^ date and time, including time zone- | PGdate -- ^ calendar date (year, month, day)- | PGtime -- ^ time of day (no time zone)- | PGtimetz -- ^ time of day, including time zone- | PGinterval -- ^ time span- | PGuuid -- ^ universally unique identifier- | PGinet -- ^ IPv4 or IPv6 host address- | PGjson -- ^ textual JSON data- | PGjsonb -- ^ binary JSON data, decomposed- | PGvararray NullityType -- ^ variable length array- | PGfixarray [Nat] NullityType -- ^ fixed length array- | PGenum [Symbol] -- ^ enumerated (enum) types are data types that comprise a static, ordered set of values.- | PGcomposite RowType -- ^ a composite type represents the structure of a row or record; it is essentially just a list of field names and their data types.- | PGtsvector -- ^ A tsvector value is a sorted list of distinct lexemes, which are words that have been normalized to merge different variants of the same word.- | PGtsquery -- ^ A tsquery value stores lexemes that are to be searched for- | UnsafePGType Symbol -- ^ an escape hatch for unsupported PostgreSQL types---- | `NullityType` encodes the potential presence or definite absence of a--- @NULL@ allowing operations which are sensitive to such to be well typed.------ >>> :kind 'Null 'PGint4--- 'Null 'PGint4 :: NullityType--- >>> :kind 'NotNull ('PGvarchar 50)--- 'NotNull ('PGvarchar 50) :: NullityType-data NullityType- = Null PGType -- ^ @NULL@ may be present- | NotNull PGType -- ^ @NULL@ is absent---- | The constraint operator, `:=>` is a type level pair--- between a "constraint" and some type, for use in pairing--- a `ColumnConstraint` with a `NullityType` to produce a `ColumnType`--- or a `TableConstraints` and a `ColumnsType` to produce a `TableType`.-type (:=>) constraint ty = '(constraint,ty)-infixr 7 :=>---- | `ColumnConstraint` encodes the availability of @DEFAULT@ for inserts and updates.--- A column can be assigned a default value.--- A data `Squeal.PostgreSQL.Manipulations.Manipulation` command can also--- request explicitly that a column be set to its default value,--- without having to know what that value is.-data ColumnConstraint- = Def -- ^ @DEFAULT@ is available for inserts and updates- | NoDef -- ^ @DEFAULT@ is unavailable for inserts and updates---- | `ColumnType` encodes the allowance of @DEFAULT@ and @NULL@ and the--- base `PGType` for a column.------ >>> :set -XTypeFamilies -XTypeInType--- >>> import GHC.TypeLits--- >>> type family IdColumn :: ColumnType where IdColumn = 'Def :=> 'NotNull 'PGint4--- >>> type family EmailColumn :: ColumnType where EmailColumn = 'NoDef :=> 'Null 'PGtext-type ColumnType = (ColumnConstraint,NullityType)---- | `ColumnsType` is a row of `ColumnType`s.------ >>> :{--- type family UsersColumns :: ColumnsType where--- UsersColumns =--- '[ "name" ::: 'NoDef :=> 'NotNull 'PGtext--- , "id" ::: 'Def :=> 'NotNull 'PGint4--- ]--- :}-type ColumnsType = [(Symbol,ColumnType)]---- | `TableConstraint` encodes various forms of data constraints--- of columns in a table.--- `TableConstraint`s give you as much control over the data in your tables--- as you wish. If a user attempts to store data in a column that would--- violate a constraint, an error is raised. This applies--- even if the value came from the default value definition.-data TableConstraint- = Check [Symbol]- | Unique [Symbol]- | PrimaryKey [Symbol]- | ForeignKey [Symbol] Symbol [Symbol]--{- | A `TableConstraints` is a row of `TableConstraint`s.-->>> :{-type family UsersConstraints :: TableConstraints where- UsersConstraints = '[ "pk_users" ::: 'PrimaryKey '["id"] ]-:}--}-type TableConstraints = [(Symbol,TableConstraint)]---- | A `ForeignKey` must reference columns that either are--- a `PrimaryKey` or form a `Unique` constraint.-type family Uniquely- (key :: [Symbol])- (constraints :: TableConstraints) :: Constraint where- Uniquely key (uq ::: 'Unique key ': constraints) = ()- Uniquely key (pk ::: 'PrimaryKey key ': constraints) = ()- Uniquely key (_ ': constraints) = Uniquely key constraints---- | `TableType` encodes a row of constraints on a table as well as the types--- of its columns.------ >>> :{--- type family UsersTable :: TableType where--- UsersTable =--- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>--- '[ "id" ::: 'Def :=> 'NotNull 'PGint4--- , "name" ::: 'NoDef :=> 'NotNull 'PGtext--- ]--- :}-type TableType = (TableConstraints,ColumnsType)--{- | A `RowType` is a row of `NullityType`. They correspond to Haskell-record types by means of `Squeal.PostgreSQL.Binary.RowPG` and are used in many places.-->>> :{-type family PersonRow :: RowType where- PersonRow =- '[ "name" ::: 'NotNull 'PGtext- , "age" ::: 'NotNull 'PGint4- , "dateOfBirth" ::: 'Null 'PGdate- ]-:}--}-type RowType = [(Symbol,NullityType)]--{- | `FromType` is a row of `RowType`s. It can be thought of as-a product, or horizontal gluing and is used in `Squeal.PostgreSQL.Query.FromClause`s-and `Squeal.PostgreSQL.Query.TableExpression`s.--}-type FromType = [(Symbol,RowType)]---- | `ColumnsToRow` removes column constraints.-type family ColumnsToRow (columns :: ColumnsType) :: RowType where- ColumnsToRow '[] = '[]- ColumnsToRow (column ::: constraint :=> ty ': columns) =- column ::: ty ': ColumnsToRow columns---- | `TableToColumns` removes table constraints.-type family TableToColumns (table :: TableType) :: ColumnsType where- TableToColumns (constraints :=> columns) = columns---- | Convert a table to a row type.-type family TableToRow (table :: TableType) :: RowType where- TableToRow tab = ColumnsToRow (TableToColumns tab)---- | Numeric Postgres types.-type PGNum =- '[ 'PGint2, 'PGint4, 'PGint8, 'PGnumeric, 'PGfloat4, 'PGfloat8]---- | Floating Postgres types.-type PGFloating = '[ 'PGfloat4, 'PGfloat8, 'PGnumeric]---- | Integral Postgres types.-type PGIntegral = '[ 'PGint2, 'PGint4, 'PGint8]---- | `PGTypeOf` forgets about @NULL@ and any column constraints.-type family PGTypeOf (ty :: NullityType) :: PGType where- PGTypeOf (nullity pg) = pg---- | Equality constraint on the underlying `PGType` of two columns.-class SamePGType- (ty0 :: (Symbol,ColumnType)) (ty1 :: (Symbol,ColumnType)) where-instance ty0 ~ ty1 => SamePGType- (alias0 ::: def0 :=> nullity0 ty0)- (alias1 ::: def1 :=> nullity1 ty1)---- | `AllNotNull` is a constraint that proves a `ColumnsType` has no @NULL@s.-type family AllNotNull (columns :: ColumnsType) :: Constraint where- AllNotNull '[] = ()- AllNotNull (column ::: def :=> 'NotNull ty ': columns) = AllNotNull columns---- | `NotAllNull` is a constraint that proves a `ColumnsType` has some--- @NOT NULL@.-type family NotAllNull (columns :: ColumnsType) :: Constraint where- NotAllNull (column ::: def :=> 'NotNull ty ': columns) = ()- NotAllNull (column ::: def :=> 'Null ty ': columns) = NotAllNull columns---- | `NullifyType` is an idempotent that nullifies a `NullityType`.-type family NullifyType (ty :: NullityType) :: NullityType where- NullifyType ('Null ty) = 'Null ty- NullifyType ('NotNull ty) = 'Null ty---- | `NullifyRow` is an idempotent that nullifies a `RowType`.-type family NullifyRow (columns :: RowType) :: RowType where- NullifyRow '[] = '[]- NullifyRow (column ::: ty ': columns) =- column ::: NullifyType ty ': NullifyRow columns---- | `NullifyFrom` is an idempotent that nullifies a `FromType`--- used to nullify the left or right hand side of an outer join--- in a `Squeal.PostgreSQL.Query.FromClause`.-type family NullifyFrom (tables :: FromType) :: FromType where- NullifyFrom '[] = '[]- NullifyFrom (table ::: columns ': tables) =- table ::: NullifyRow columns ': NullifyFrom tables---- | @Create alias x xs@ adds @alias ::: x@ to the end of @xs@ and is used in--- `Squeal.PostgreSQL.Definition.createTable` statements and in @ALTER TABLE@--- `Squeal.PostgreSQL.Definition.addColumn`.-type family Create alias x xs where- Create alias x '[] = '[alias ::: x]- Create alias x (alias ::: y ': xs) = TypeError- ('Text "Create: alias "- ':<>: 'ShowType alias- ':<>: 'Text "already in use")- Create alias y (x ': xs) = x ': Create alias y xs---- | @Drop alias xs@ removes the type associated with @alias@ in @xs@--- and is used in `Squeal.PostgreSQL.Definition.dropTable` statements--- and in @ALTER TABLE@ `Squeal.PostgreSQL.Definition.dropColumn` statements.-type family Drop alias xs where- Drop alias ((alias ::: x) ': xs) = xs- Drop alias (x ': xs) = x ': Drop alias xs---- | @Alter alias x xs@ replaces the type associated with an @alias@ in @xs@--- with the type @x@ and is used in `Squeal.PostgreSQL.Definition.alterTable`--- and `Squeal.PostgreSQL.Definition.alterColumn`.-type family Alter alias x xs where- Alter alias x1 (alias ::: x0 ': xs) = alias ::: x1 ': xs- Alter alias x1 (x0 ': xs) = x0 ': Alter alias x1 xs---- | @Rename alias0 alias1 xs@ replaces the alias @alias0@ by @alias1@ in @xs@--- and is used in `Squeal.PostgreSQL.Definition.alterTableRename` and--- `Squeal.PostgreSQL.Definition.renameColumn`.-type family Rename alias0 alias1 xs where- Rename alias0 alias1 ((alias0 ::: x0) ': xs) = (alias1 ::: x0) ': xs- Rename alias0 alias1 (x ': xs) = x ': Rename alias0 alias1 xs---- | Check if a `TableConstraint` involves a column-type family ConstraintInvolves column constraint where- ConstraintInvolves column ('Check columns) = column `Elem` columns- ConstraintInvolves column ('Unique columns) = column `Elem` columns- ConstraintInvolves column ('PrimaryKey columns) = column `Elem` columns- ConstraintInvolves column ('ForeignKey columns tab refcolumns)- = column `Elem` columns---- | Drop all `TableConstraint`s that involve a column-type family DropIfConstraintsInvolve column constraints where- DropIfConstraintsInvolve column '[] = '[]- DropIfConstraintsInvolve column (alias ::: constraint ': constraints)- = If (ConstraintInvolves column constraint)- (DropIfConstraintsInvolve column constraints)- (alias ::: constraint ': DropIfConstraintsInvolve column constraints)---- | A `SchemumType` is a user-defined type, either a `Table`,--- `View` or `Typedef`.-data SchemumType- = Table TableType- | View RowType- | Typedef PGType--{- | The schema of a database consists of a list of aliased,-user-defined `SchemumType`s.-->>> :{-type family Schema :: SchemaType where- Schema =- '[ "users" ::: 'Table (- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "name" ::: 'NoDef :=> 'NotNull 'PGtext- ])- , "emails" ::: 'Table (- '[ "pk_emails" ::: 'PrimaryKey '["id"]- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]- ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4- , "email" ::: 'NoDef :=> 'Null 'PGtext- ])- ]-:}--}-type SchemaType = [(Symbol,SchemumType)]--{- |-A database contains one or more named schemas, which in turn contain tables.-The same object name can be used in different schemas without conflict;-for example, both schema1 and myschema can contain tables named mytable.-Unlike databases, schemas are not rigidly separated:-a user can access objects in any of the schemas in the database they are connected to,-if they have privileges to do so.--There are several reasons why one might want to use schemas:-- * To allow many users to use one database without interfering with each other.- * To organize database objects into logical groups to make them more manageable.- * Third-party applications can be put into separate schemas- so they do not collide with the names of other objects.--}-type SchemasType = [(Symbol,SchemaType)]---- | A type family to use for a single schema database.-type family Public (schema :: SchemaType) :: SchemasType- where Public schema = '["public" ::: schema]---- | `IsPGlabel` looks very much like the `IsLabel` class. Whereas--- the overloaded label, `fromLabel` is used for column references,--- `label`s are used for enum terms. A `label` is called with--- type application like `label @"beef"`.-class IsPGlabel (label :: Symbol) expr where label :: expr-instance label ~ label1- => IsPGlabel label (PGlabel label1) where label = PGlabel-instance labels ~ '[label]- => IsPGlabel label (NP PGlabel labels) where label = PGlabel :* Nil--- | A `PGlabel` unit type with an `IsPGlabel` instance-data PGlabel (label :: Symbol) = PGlabel-instance KnownSymbol label => RenderSQL (PGlabel label) where- renderSQL _ = "\'" <> renderSymbol @label <> "\'"-instance All KnownSymbol labels => RenderSQL (NP PGlabel labels) where- renderSQL- = commaSeparated- . hcollapse- . hcmap (Proxy @KnownSymbol) (K . renderSQL)---- | Is a type a valid JSON key?-type PGJsonKey = '[ 'PGint2, 'PGint4, 'PGtext ]---- | Is a type a valid JSON type?-type PGJsonType = '[ 'PGjson, 'PGjsonb ]---- | Utility class for `AllUnique` to provide nicer error messages.-class IsNotElem x isElem where-instance IsNotElem x 'False where-instance (TypeError ( 'Text "Cannot assign to "- ':<>: 'ShowType alias- ':<>: 'Text " more than once"))- => IsNotElem '(alias, a) 'True where---- | No elem of @xs@ appears more than once, in the context of assignment.-class AllUnique (xs :: [(Symbol, a)]) where-instance AllUnique '[] where-instance (IsNotElem x (Elem x xs), AllUnique xs) => AllUnique (x ': xs) where
+ src/Squeal/PostgreSQL/Session.hs view
@@ -0,0 +1,295 @@+{-|+Module: Squeal.PostgreSQL.Session+Description: sessions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Using Squeal in your application will come down to defining+the @db@ of your database and including @PQ db db@ in your+application's monad transformer stack, giving it an instance of `MonadPQ`.+-}++{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+{-# LANGUAGE+ DefaultSignatures+ , FunctionalDependencies+ , FlexibleContexts+ , FlexibleInstances+ , InstanceSigs+ , OverloadedStrings+ , PolyKinds+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session+ ( PQ (PQ, unPQ)+ , runPQ+ , execPQ+ , evalPQ+ , withConnection+ ) where++import Control.Category+import Control.Monad.Except+import Control.Monad.Morph+import Control.Monad.Reader+import UnliftIO (MonadUnliftIO (..), bracket, throwIO)+import Data.ByteString (ByteString)+import Data.Foldable+import Data.Functor ((<&>))+import Data.Kind+import Data.Traversable+import Generics.SOP+import PostgreSQL.Binary.Encoding (encodingBytes)+import Prelude hiding (id, (.))++import qualified Control.Monad.Fail as Fail+import qualified Database.PostgreSQL.LibPQ as LibPQ+import qualified PostgreSQL.Binary.Encoding as Encoding++import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Session.Connection+import Squeal.PostgreSQL.Session.Encode+import Squeal.PostgreSQL.Session.Exception+import Squeal.PostgreSQL.Session.Indexed+import Squeal.PostgreSQL.Session.Oid+import Squeal.PostgreSQL.Session.Monad+import Squeal.PostgreSQL.Session.Result+import Squeal.PostgreSQL.Session.Statement+import Squeal.PostgreSQL.Type.Schema++-- | We keep track of the schema via an Atkey indexed state monad transformer,+-- `PQ`.+newtype PQ+ (db0 :: SchemasType)+ (db1 :: SchemasType)+ (m :: Type -> Type)+ (x :: Type) =+ PQ { unPQ :: K LibPQ.Connection db0 -> m (K x db1) }++instance Monad m => Functor (PQ db0 db1 m) where+ fmap f (PQ pq) = PQ $ \ conn -> do+ K x <- pq conn+ return $ K (f x)++-- | Run a `PQ` and keep the result and the `LibPQ.Connection`.+runPQ+ :: Functor m+ => PQ db0 db1 m x+ -> K LibPQ.Connection db0+ -> m (x, K LibPQ.Connection db1)+runPQ (PQ pq) conn = (\ x -> (unK x, K (unK conn))) <$> pq conn+ -- K x <- pq conn+ -- return (x, K (unK conn))++-- | Execute a `PQ` and discard the result but keep the `LibPQ.Connection`.+execPQ+ :: Functor m+ => PQ db0 db1 m x+ -> K LibPQ.Connection db0+ -> m (K LibPQ.Connection db1)+execPQ (PQ pq) conn = mapKK (\ _ -> unK conn) <$> pq conn++-- | Evaluate a `PQ` and discard the `LibPQ.Connection` but keep the result.+evalPQ+ :: Functor m+ => PQ db0 db1 m x+ -> K LibPQ.Connection db0+ -> m x+evalPQ (PQ pq) conn = unK <$> pq conn++instance IndexedMonadTrans PQ where++ pqAp (PQ f) (PQ x) = PQ $ \ conn -> do+ K f' <- f conn+ K x' <- x (K (unK conn))+ return $ K (f' x')++ pqBind f (PQ x) = PQ $ \ conn -> do+ K x' <- x conn+ unPQ (f x') (K (unK conn))++instance IndexedMonadTransPQ PQ where++ define (UnsafeDefinition q) = PQ $ \ (K conn) -> do+ resultMaybe <- liftIO $ LibPQ.exec conn q+ case resultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.exec"+ Just result -> K <$> okResult_ result++instance (MonadIO io, db0 ~ db, db1 ~ db) => MonadPQ db (PQ db0 db1 io) where++ executeParams (Manipulation encode decode (UnsafeManipulation q)) x =+ PQ $ \ kconn@(K conn) -> do+ let+ formatParam+ :: forall param. OidOfNull db param+ => K (Maybe Encoding.Encoding) param+ -> io (K (Maybe (LibPQ.Oid, ByteString, LibPQ.Format)) param)+ formatParam (K maybeEncoding) = do+ oid <- liftIO $ runReaderT (oidOfNull @db @param) kconn+ return . K $ maybeEncoding <&> \encoding ->+ (oid, encodingBytes encoding, LibPQ.Binary)+ encodedParams <- liftIO $ runReaderT (runEncodeParams encode x) kconn+ formattedParams <- hcollapse <$>+ hctraverse' (Proxy @(OidOfNull db)) formatParam encodedParams+ resultMaybe <- liftIO $+ LibPQ.execParams conn (q <> ";") formattedParams LibPQ.Binary+ case resultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.execParams"+ Just result -> do+ okResult_ result+ return $ K (Result decode result)+ executeParams (Query encode decode q) x =+ executeParams (Manipulation encode decode (queryStatement q)) x++ executePrepared (Manipulation encode decode (UnsafeManipulation q :: Manipulation '[] db params row)) list =+ PQ $ \ kconn@(K conn) -> liftIO $ do+ let+ temp = "temporary_statement"+ oidOfParam :: forall p. OidOfNull db p => (IO :.: K LibPQ.Oid) p+ oidOfParam = Comp $ K <$> runReaderT (oidOfNull @db @p) kconn+ oidsOfParams :: NP (IO :.: K LibPQ.Oid) params+ oidsOfParams = hcpure (Proxy @(OidOfNull db)) oidOfParam+ oids <- hcollapse <$> hsequence' oidsOfParams+ prepResultMaybe <- LibPQ.prepare conn temp (q <> ";") (Just oids)+ case prepResultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.prepare"+ Just prepResult -> okResult_ prepResult+ results <- for list $ \ params -> do+ encodedParams <- runReaderT (runEncodeParams encode params) kconn+ let+ formatParam encoding = (encodingBytes encoding, LibPQ.Binary)+ formattedParams =+ [ formatParam <$> maybeParam+ | maybeParam <- hcollapse encodedParams+ ]+ resultMaybe <-+ LibPQ.execPrepared conn temp formattedParams LibPQ.Binary+ case resultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.execPrepared"+ Just result -> do+ okResult_ result+ return $ Result decode result+ deallocResultMaybe <- LibPQ.exec conn ("DEALLOCATE " <> temp <> ";")+ case deallocResultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.exec"+ Just deallocResult -> okResult_ deallocResult+ return (K results)+ executePrepared (Query encode decode q) list =+ executePrepared (Manipulation encode decode (queryStatement q)) list++ executePrepared_ (Manipulation encode _ (UnsafeManipulation q :: Manipulation '[] db params row)) list =+ PQ $ \ kconn@(K conn) -> liftIO $ do+ let+ temp = "temporary_statement"+ oidOfParam :: forall p. OidOfNull db p => (IO :.: K LibPQ.Oid) p+ oidOfParam = Comp $ K <$> runReaderT (oidOfNull @db @p) kconn+ oidsOfParams :: NP (IO :.: K LibPQ.Oid) params+ oidsOfParams = hcpure (Proxy @(OidOfNull db)) oidOfParam+ oids <- hcollapse <$> hsequence' oidsOfParams+ prepResultMaybe <- LibPQ.prepare conn temp (q <> ";") (Just oids)+ case prepResultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.prepare"+ Just prepResult -> okResult_ prepResult+ for_ list $ \ params -> do+ encodedParams <- runReaderT (runEncodeParams encode params) kconn+ let+ formatParam encoding = (encodingBytes encoding, LibPQ.Binary)+ formattedParams =+ [ formatParam <$> maybeParam+ | maybeParam <- hcollapse encodedParams+ ]+ resultMaybe <-+ LibPQ.execPrepared conn temp formattedParams LibPQ.Binary+ case resultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.execPrepared"+ Just result -> okResult_ result+ deallocResultMaybe <- LibPQ.exec conn ("DEALLOCATE " <> temp <> ";")+ case deallocResultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.exec"+ Just deallocResult -> okResult_ deallocResult+ return (K ())+ executePrepared_ (Query encode decode q) list =+ executePrepared_ (Manipulation encode decode (queryStatement q)) list++instance (Monad m, db0 ~ db1)+ => Applicative (PQ db0 db1 m) where+ pure x = PQ $ \ _conn -> pure (K x)+ (<*>) = pqAp++instance (Monad m, db0 ~ db1)+ => Monad (PQ db0 db1 m) where+ return = pure+ (>>=) = flip pqBind++instance (Monad m, db0 ~ db1)+ => Fail.MonadFail (PQ db0 db1 m) where+ fail = Fail.fail++instance db0 ~ db1 => MFunctor (PQ db0 db1) where+ hoist f (PQ pq) = PQ (f . pq)++instance db0 ~ db1 => MonadTrans (PQ db0 db1) where+ lift m = PQ $ \ _conn -> do+ x <- m+ return (K x)++instance db0 ~ db1 => MMonad (PQ db0 db1) where+ embed f (PQ pq) = PQ $ \ conn -> do+ evalPQ (f (pq conn)) conn++instance (MonadIO m, schema0 ~ schema1)+ => MonadIO (PQ schema0 schema1 m) where+ liftIO = lift . liftIO++instance (MonadUnliftIO m, db0 ~ db1)+ => MonadUnliftIO (PQ db0 db1 m) where+ withRunInIO+ :: ((forall a . PQ db0 schema1 m a -> IO a) -> IO b)+ -> PQ db0 schema1 m b+ withRunInIO inner = PQ $ \conn ->+ withRunInIO $ \(run :: (forall x . m x -> IO x)) ->+ K <$> inner (\pq -> run $ unK <$> unPQ pq conn)++instance (Monad m, Semigroup r, db0 ~ db1) => Semigroup (PQ db0 db1 m r) where+ f <> g = pqAp (fmap (<>) f) g++instance (Monad m, Monoid r, db0 ~ db1) => Monoid (PQ db0 db1 m r) where+ mempty = pure mempty++-- | Do `connectdb` and `finish` before and after a computation.+withConnection+ :: forall db0 db1 io x+ . MonadUnliftIO io+ => ByteString+ -> PQ db0 db1 io x+ -> io x+withConnection connString action = do+ K x <- bracket (connectdb connString) finish (unPQ action)+ return x++okResult_ :: MonadIO io => LibPQ.Result -> io ()+okResult_ result = liftIO $ do+ status <- LibPQ.resultStatus result+ case status of+ LibPQ.CommandOk -> return ()+ LibPQ.TuplesOk -> return ()+ _ -> do+ stateCodeMaybe <- LibPQ.resultErrorField result LibPQ.DiagSqlstate+ case stateCodeMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.resultErrorField"+ Just stateCode -> do+ msgMaybe <- LibPQ.resultErrorMessage result+ case msgMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.resultErrorMessage"+ Just msg -> throwIO . SQLException $ SQLState status stateCode msg
+ src/Squeal/PostgreSQL/Session/Connection.hs view
@@ -0,0 +1,78 @@+{-|+Module: Squeal.PostgreSQL.Session.Connection+Description: database connections+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++database connections+-}++{-# LANGUAGE+ DataKinds+ , PolyKinds+ , RankNTypes+ , TypeOperators+#-}++module Squeal.PostgreSQL.Session.Connection+ ( LibPQ.Connection+ , connectdb+ , finish+ , lowerConnection+ , SOP.K (..)+ , SOP.unK+ ) where++import Control.Monad.IO.Class+import Data.ByteString (ByteString)++import Squeal.PostgreSQL.Type.Schema++import qualified Generics.SOP as SOP+import qualified Database.PostgreSQL.LibPQ as LibPQ++-- $setup+-- >>> import Squeal.PostgreSQL++{- | Makes a new connection to the database server.++This function opens a new database connection using the parameters taken+from the string conninfo.++The passed string can be empty to use all default parameters, or it can+contain one or more parameter settings separated by whitespace.+Each parameter setting is in the form keyword = value. Spaces around the equal+sign are optional. To write an empty value or a value containing spaces,+surround it with single quotes, e.g., keyword = 'a value'. Single quotes and+backslashes within the value must be escaped with a backslash, i.e., ' and \.++To specify the schema you wish to connect with, use type application.++>>> :set -XDataKinds+>>> :set -XPolyKinds+>>> :set -XTypeOperators+>>> type DB = '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint2])]]+>>> :set -XTypeApplications+>>> :set -XOverloadedStrings+>>> conn <- connectdb @DB "host=localhost port=5432 dbname=exampledb"++Note that, for now, squeal doesn't offer any protection from connecting+with the wrong schema!+-}+connectdb+ :: forall (db :: SchemasType) io+ . MonadIO io+ => ByteString -- ^ conninfo+ -> io (SOP.K LibPQ.Connection db)+connectdb = fmap SOP.K . liftIO . LibPQ.connectdb++-- | Closes the connection to the server.+finish :: MonadIO io => SOP.K LibPQ.Connection db -> io ()+finish = liftIO . LibPQ.finish . SOP.unK++-- | Safely `lowerConnection` to a smaller schema.+lowerConnection+ :: SOP.K LibPQ.Connection (schema ': db)+ -> SOP.K LibPQ.Connection db+lowerConnection (SOP.K conn) = SOP.K conn
+ src/Squeal/PostgreSQL/Session/Decode.hs view
@@ -0,0 +1,445 @@+{-|+Module: Squeal.PostgreSQL.Session.Decode+Description: decoding of result values+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++decoding of result values+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , DataKinds+ , DerivingStrategies+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GeneralizedNewtypeDeriving+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , PolyKinds+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session.Decode+ ( -- * Decode Types+ FromPG (..)+ , devalue+ , rowValue+ -- * Decode Rows+ , DecodeRow (..)+ , decodeRow+ , runDecodeRow+ , genericRow+ -- * Decoding Classes+ , FromValue (..)+ , FromField (..)+ , FromArray (..)+ , StateT (..)+ , ExceptT (..)+ ) where++import BinaryParser+import Control.Applicative+import Control.Arrow+import Control.Monad+import Control.Monad.Except+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Trans.Maybe+import Data.Bits+import Data.Int (Int16, Int32, Int64)+import Data.Kind+import Data.Scientific (Scientific)+import Data.Time (Day, TimeOfDay, TimeZone, LocalTime, UTCTime, DiffTime)+import Data.UUID.Types (UUID)+import Data.Vector (Vector)+import Database.PostgreSQL.LibPQ (Oid(Oid))+import GHC.OverloadedLabels+import GHC.TypeLits+import Network.IP.Addr (NetAddr, IP)+import PostgreSQL.Binary.Decoding hiding (Composite)+import Unsafe.Coerce++import qualified Data.Aeson as Aeson+import qualified Data.ByteString.Lazy as Lazy (ByteString)+import qualified Data.ByteString as Strict (ByteString)+import qualified Data.Text.Lazy as Lazy (Text)+import qualified Data.Text as Strict (Text)+import qualified Data.Text as Strict.Text+import qualified Data.Vector as Vector+import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP++import Squeal.PostgreSQL.Expression.Range+import Squeal.PostgreSQL.Type+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.PG+import Squeal.PostgreSQL.Type.Schema++-- | Converts a `Value` type from @postgresql-binary@ for use in+-- the `fromPG` method of `FromPG`.+devalue :: Value x -> StateT Strict.ByteString (Except Strict.Text) x+devalue = unsafeCoerce++revalue :: StateT Strict.ByteString (Except Strict.Text) x -> Value x+revalue = unsafeCoerce++{- |+>>> :set -XTypeFamilies+>>> :{+data Complex = Complex+ { real :: Double+ , imaginary :: Double+ }+instance IsPG Complex where+ type PG Complex = 'PGcomposite '[+ "re" ::: 'NotNull 'PGfloat8,+ "im" ::: 'NotNull 'PGfloat8]+instance FromPG Complex where+ fromPG = rowValue $ do+ re <- #re+ im <- #im+ return Complex {real = re, imaginary = im}+:}+-}+rowValue+ :: (PG y ~ 'PGcomposite row, SOP.SListI row)+ => DecodeRow row y+ -> StateT Strict.ByteString (Except Strict.Text) y+rowValue decoder = devalue $+ let+ -- <number of fields: 4 bytes>+ -- [for each field]+ -- <OID of field's type: sizeof(Oid) bytes>+ -- [if value is NULL]+ -- <-1: 4 bytes>+ -- [else]+ -- <length of value: 4 bytes>+ -- <value: <length> bytes>+ -- [end if]+ -- [end for]+ comp = valueParser $ do+ unitOfSize 4+ SOP.hsequence' $ SOP.hpure $ SOP.Comp $ do+ unitOfSize 4+ len :: Int32 <- sized 4 int+ if len == -1+ then return (SOP.K Nothing)+ else SOP.K . Just <$> bytesOfSize (fromIntegral len)+ in fn (runDecodeRow decoder <=< comp)++-- | A `FromPG` constraint gives a parser from the binary format of+-- a PostgreSQL `PGType` into a Haskell `Type`.+class IsPG y => FromPG y where+ {- |+ >>> :set -XMultiParamTypeClasses -XGeneralizedNewtypeDeriving -XDerivingStrategies -XDerivingVia -XUndecidableInstances+ >>> import GHC.Generics as GHC+ >>> :{+ newtype UserId = UserId { getId :: Int64 }+ deriving newtype (IsPG, FromPG)+ :}++ >>> :{+ data Complex = Complex+ { real :: Double+ , imaginary :: Double+ } deriving stock GHC.Generic+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)+ deriving (IsPG, FromPG) via (Composite Complex)+ :}++ >>> :{+ data Direction = North | South | East | West+ deriving stock GHC.Generic+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)+ deriving (IsPG, FromPG) via (Enumerated Direction)+ :}++ -}+ fromPG :: StateT Strict.ByteString (Except Strict.Text) y+instance FromPG Bool where+ fromPG = devalue bool+instance FromPG Int16 where+ fromPG = devalue int+instance FromPG Int32 where+ fromPG = devalue int+instance FromPG Int64 where+ fromPG = devalue int+instance FromPG Oid where+ fromPG = devalue $ Oid <$> int+instance FromPG Float where+ fromPG = devalue float4+instance FromPG Double where+ fromPG = devalue float8+instance FromPG Scientific where+ fromPG = devalue numeric+instance FromPG Money where+ fromPG = devalue $ Money <$> int+instance FromPG UUID where+ fromPG = devalue uuid+instance FromPG (NetAddr IP) where+ fromPG = devalue inet+instance FromPG Char where+ fromPG = devalue char+instance FromPG Strict.Text where+ fromPG = devalue text_strict+instance FromPG Lazy.Text where+ fromPG = devalue text_lazy+instance FromPG String where+ fromPG = devalue $ Strict.Text.unpack <$> text_strict+instance FromPG Strict.ByteString where+ fromPG = devalue bytea_strict+instance FromPG Lazy.ByteString where+ fromPG = devalue bytea_lazy+instance FromPG Day where+ fromPG = devalue date+instance FromPG TimeOfDay where+ fromPG = devalue time_int+instance FromPG (TimeOfDay, TimeZone) where+ fromPG = devalue timetz_int+instance FromPG LocalTime where+ fromPG = devalue timestamp_int+instance FromPG UTCTime where+ fromPG = devalue timestamptz_int+instance FromPG DiffTime where+ fromPG = devalue interval_int+instance FromPG Aeson.Value where+ fromPG = devalue json_ast+instance Aeson.FromJSON x => FromPG (Json x) where+ fromPG = devalue $ Json <$>+ json_bytes (left Strict.Text.pack . Aeson.eitherDecodeStrict)+instance Aeson.FromJSON x => FromPG (Jsonb x) where+ fromPG = devalue $ Jsonb <$>+ jsonb_bytes (left Strict.Text.pack . Aeson.eitherDecodeStrict)+instance (FromArray '[] ty y, ty ~ NullPG y)+ => FromPG (VarArray (Vector y)) where+ fromPG =+ let+ rep n x = VarArray <$> Vector.replicateM n x+ in+ devalue . array $ dimensionArray rep+ (fromArray @'[] @(NullPG y))+instance (FromArray '[] ty y, ty ~ NullPG y)+ => FromPG (VarArray [y]) where+ fromPG =+ let+ rep n x = VarArray <$> replicateM n x+ in+ devalue . array $ dimensionArray rep+ (fromArray @'[] @(NullPG y))+instance FromArray dims ty y => FromPG (FixArray y) where+ fromPG = devalue $ FixArray <$> array (fromArray @dims @ty @y)+instance+ ( SOP.IsEnumType y+ , SOP.HasDatatypeInfo y+ , LabelsPG y ~ labels+ ) => FromPG (Enumerated y) where+ fromPG =+ let+ greadConstructor+ :: SOP.All ((~) '[]) xss+ => NP SOP.ConstructorInfo xss+ -> String+ -> Maybe (SOP.SOP SOP.I xss)+ greadConstructor Nil _ = Nothing+ greadConstructor (constructor :* constructors) name =+ if name == SOP.constructorName constructor+ then Just (SOP.SOP (SOP.Z Nil))+ else SOP.SOP . SOP.S . SOP.unSOP <$>+ greadConstructor constructors name+ in+ devalue+ $ fmap Enumerated+ . enum+ $ fmap SOP.to+ . greadConstructor+ (SOP.constructorInfo (SOP.datatypeInfo (SOP.Proxy @y)))+ . Strict.Text.unpack+instance+ ( SOP.IsRecord y ys+ , SOP.AllZip FromField row ys+ , RowPG y ~ row+ ) => FromPG (Composite y) where+ fromPG = rowValue (Composite <$> genericRow)+instance FromPG y => FromPG (Range y) where+ fromPG = devalue $ do+ flag <- byte+ if testBit flag 0 then return Empty else do+ lower <-+ if testBit flag 3+ then return Infinite+ else do+ len <- sized 4 int+ l <- sized len (revalue fromPG)+ return $ if testBit flag 1 then Closed l else Open l+ upper <-+ if testBit flag 4+ then return Infinite+ else do+ len <- sized 4 int+ l <- sized len (revalue fromPG)+ return $ if testBit flag 2 then Closed l else Open l+ return $ NonEmpty lower upper++-- | A `FromValue` constraint lifts the `FromPG` parser+-- to a decoding of a @NullityType@ to a `Type`,+-- decoding `Null`s to `Maybe`s. You should not define instances for+-- `FromValue`, just use the provided instances.+class FromValue (ty :: NullType) (y :: Type) where+ fromValue :: Maybe Strict.ByteString -> Either Strict.Text y+instance (FromPG y, pg ~ PG y) => FromValue ('NotNull pg) y where+ fromValue = \case+ Nothing -> throwError "fromField: saw NULL when expecting NOT NULL"+ Just bytestring -> valueParser (revalue fromPG) bytestring+instance (FromPG y, pg ~ PG y) => FromValue ('Null pg) (Maybe y) where+ fromValue = \case+ Nothing -> return Nothing+ Just bytestring -> fmap Just $ valueParser (revalue fromPG) bytestring++-- | A `FromField` constraint lifts the `FromPG` parser+-- to a decoding of a @(Symbol, NullityType)@ to a `Type`,+-- decoding `Null`s to `Maybe`s. You should not define instances for+-- `FromField`, just use the provided instances.+class FromField (field :: (Symbol, NullType)) (y :: (Symbol, Type)) where+ fromField :: Maybe Strict.ByteString -> Either Strict.Text (SOP.P y)+instance (FromValue ty y, fld0 ~ fld1)+ => FromField (fld0 ::: ty) (fld1 ::: y) where+ fromField = fmap SOP.P . fromValue @ty++-- | A `FromArray` constraint gives a decoding to a Haskell `Type`+-- from the binary format of a PostgreSQL fixed-length array.+-- You should not define instances for+-- `FromArray`, just use the provided instances.+class FromArray (dims :: [Nat]) (ty :: NullType) (y :: Type) where+ fromArray :: Array y+instance (FromPG y, pg ~ PG y) => FromArray '[] ('NotNull pg) y where+ fromArray = valueArray (revalue fromPG)+instance (FromPG y, pg ~ PG y) => FromArray '[] ('Null pg) (Maybe y) where+ fromArray = nullableValueArray (revalue fromPG)+instance+ ( SOP.IsProductType product ys+ , Length ys ~ dim+ , SOP.All ((~) y) ys+ , FromArray dims ty y )+ => FromArray (dim ': dims) ty product where+ fromArray =+ let+ rep _ = fmap (SOP.to . SOP.SOP . SOP.Z) . replicateMN+ in+ dimensionArray rep (fromArray @dims @ty @y)++replicateMN+ :: forall x xs m. (SOP.All ((~) x) xs, Monad m, SOP.SListI xs)+ => m x -> m (SOP.NP SOP.I xs)+replicateMN mx = SOP.hsequence' $+ SOP.hcpure (SOP.Proxy :: SOP.Proxy ((~) x)) (SOP.Comp (SOP.I <$> mx))++{- |+`DecodeRow` describes a decoding of a PostgreSQL `RowType`+into a Haskell `Type`.++`DecodeRow` has an interface given by the classes+`Functor`, `Applicative`, `Alternative`, `Monad`,+`MonadPlus`, `MonadError` `Strict.Text`, and `IsLabel`.++>>> :set -XOverloadedLabels+>>> :{+let+ decode :: DecodeRow+ '[ "fst" ::: 'NotNull 'PGint2, "snd" ::: 'NotNull ('PGchar 1)]+ (Int16, Char)+ decode = (,) <$> #fst <*> #snd+in runDecodeRow decode (SOP.K (Just "\NUL\SOH") :* SOP.K (Just "a") :* Nil)+:}+Right (1,'a')++There is also an `IsLabel` instance for `MaybeT` `DecodeRow`s, useful+for decoding outer joined rows.++>>> :{+let+ decode :: DecodeRow+ '[ "fst" ::: 'Null 'PGint2, "snd" ::: 'Null ('PGchar 1)]+ (Maybe (Int16, Char))+ decode = runMaybeT $ (,) <$> #fst <*> #snd+in runDecodeRow decode (SOP.K (Just "\NUL\SOH") :* SOP.K (Just "a") :* Nil)+:}+Right (Just (1,'a'))++-}+newtype DecodeRow (row :: RowType) (y :: Type) = DecodeRow+ { unDecodeRow :: ReaderT+ (SOP.NP (SOP.K (Maybe Strict.ByteString)) row) (Except Strict.Text) y }+ deriving newtype+ ( Functor+ , Applicative+ , Alternative+ , Monad+ , MonadPlus+ , MonadError Strict.Text )++-- | Run a `DecodeRow`.+runDecodeRow+ :: DecodeRow row y+ -> SOP.NP (SOP.K (Maybe Strict.ByteString)) row+ -> Either Strict.Text y+runDecodeRow = fmap runExcept . runReaderT . unDecodeRow++-- | Smart constructor for a `DecodeRow`.+decodeRow+ :: (SOP.NP (SOP.K (Maybe Strict.ByteString)) row -> Either Strict.Text y)+ -> DecodeRow row y+decodeRow dec = DecodeRow . ReaderT $ liftEither . dec+instance {-# OVERLAPPING #-} FromValue ty y+ => IsLabel fld (DecodeRow (fld ::: ty ': row) y) where+ fromLabel = decodeRow $ \(SOP.K b SOP.:* _) ->+ fromValue @ty b+instance {-# OVERLAPPABLE #-} IsLabel fld (DecodeRow row y)+ => IsLabel fld (DecodeRow (field ': row) y) where+ fromLabel = decodeRow $ \(_ SOP.:* bs) ->+ runDecodeRow (fromLabel @fld) bs+instance {-# OVERLAPPING #-} FromValue ty (Maybe y)+ => IsLabel fld (MaybeT (DecodeRow (fld ::: ty ': row)) y) where+ fromLabel = MaybeT . decodeRow $ \(SOP.K b SOP.:* _) ->+ fromValue @ty b+instance {-# OVERLAPPABLE #-} IsLabel fld (MaybeT (DecodeRow row) y)+ => IsLabel fld (MaybeT (DecodeRow (field ': row)) y) where+ fromLabel = MaybeT . decodeRow $ \(_ SOP.:* bs) ->+ runDecodeRow (runMaybeT (fromLabel @fld)) bs++{- | Row decoder for `SOP.Generic` records.++>>> import qualified GHC.Generics as GHC+>>> import qualified Generics.SOP as SOP+>>> data Two = Two {frst :: Int16, scnd :: String} deriving (Show, GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)+>>> :{+let+ decode :: DecodeRow '[ "frst" ::: 'NotNull 'PGint2, "scnd" ::: 'NotNull 'PGtext] Two+ decode = genericRow+in runDecodeRow decode (SOP.K (Just "\NUL\STX") :* SOP.K (Just "two") :* Nil)+:}+Right (Two {frst = 2, scnd = "two"})+-}+genericRow :: forall row y ys.+ ( SOP.IsRecord y ys+ , SOP.AllZip FromField row ys+ ) => DecodeRow row y+genericRow+ = DecodeRow+ . ReaderT+ $ fmap SOP.fromRecord+ . SOP.hsequence'+ . SOP.htrans (SOP.Proxy @FromField) (SOP.Comp . runField)+runField+ :: forall ty y. FromField ty y+ => SOP.K (Maybe Strict.ByteString) ty+ -> Except Strict.Text (SOP.P y)+runField = liftEither . fromField @ty . SOP.unK
+ src/Squeal/PostgreSQL/Session/Encode.hs view
@@ -0,0 +1,508 @@+{-|+Module: Squeal.PostgreSQL.Session.Encode+Description: encoding of statement parameters+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++encoding of statement parameters+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DataKinds+ , DefaultSignatures+ , FlexibleContexts+ , FlexibleInstances+ , LambdaCase+ , MultiParamTypeClasses+ , PolyKinds+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session.Encode+ ( -- * Encode Parameters+ EncodeParams (..)+ , genericParams+ , nilParams+ , (.*)+ , (*.)+ , aParam+ , appendParams+ -- * Encoding Classes+ , ToPG (..)+ , ToParam (..)+ , ToField (..)+ , ToArray (..)+ ) where++import ByteString.StrictBuilder+import Control.Monad+import Control.Monad.Reader+import Data.Bits+import Data.ByteString as Strict (ByteString)+import Data.ByteString.Lazy as Lazy (ByteString)+import Data.Functor.Contravariant+import Data.Int (Int16, Int32, Int64)+import Data.Kind+import Data.Scientific (Scientific)+import Data.Text as Strict (Text)+import Data.Text.Lazy as Lazy (Text)+import Data.Time (Day, TimeOfDay, TimeZone, LocalTime, UTCTime, DiffTime)+import Data.UUID.Types (UUID)+import Data.Vector (Vector)+import Data.Word (Word32)+import Foreign.C.Types (CUInt(CUInt))+import GHC.TypeLits+import Network.IP.Addr (NetAddr, IP)+import PostgreSQL.Binary.Encoding++import qualified Data.Aeson as Aeson+import qualified Data.ByteString.Lazy as Lazy.ByteString+import qualified Data.Text as Strict.Text+import qualified Database.PostgreSQL.LibPQ as LibPQ+import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP++import Squeal.PostgreSQL.Expression.Range+import Squeal.PostgreSQL.Session.Oid+import Squeal.PostgreSQL.Type+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.PG+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL (connectdb, finish)++-- | A `ToPG` constraint gives an encoding of a Haskell `Type` into+-- into the binary format of a PostgreSQL `PGType`.+class IsPG x => ToPG (db :: SchemasType) (x :: Type) where+ -- | >>> :set -XTypeApplications -XDataKinds+ -- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+ -- >>> runReaderT (toPG @'[] False) conn+ -- "\NUL"+ --+ -- >>> runReaderT (toPG @'[] (0 :: Int16)) conn+ -- "\NUL\NUL"+ --+ -- >>> runReaderT (toPG @'[] (0 :: Int32)) conn+ -- "\NUL\NUL\NUL\NUL"+ --+ -- >>> :set -XMultiParamTypeClasses -XGeneralizedNewtypeDeriving+ -- >>> newtype UserId = UserId { getUserId :: Int64 } deriving newtype (IsPG, ToPG db)+ -- >>> runReaderT (toPG @'[] (UserId 0)) conn+ -- "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL"+ --+ -- >>> finish conn+ toPG :: x -> ReaderT (SOP.K LibPQ.Connection db) IO Encoding+instance ToPG db Bool where toPG = pure . bool+instance ToPG db Int16 where toPG = pure . int2_int16+instance ToPG db Int32 where toPG = pure . int4_int32+instance ToPG db Int64 where toPG = pure . int8_int64+instance ToPG db Oid where toPG = pure . int4_word32 . getOid+instance ToPG db Float where toPG = pure . float4+instance ToPG db Double where toPG = pure . float8+instance ToPG db Scientific where toPG = pure . numeric+instance ToPG db Money where toPG = pure . int8_int64 . cents+instance ToPG db UUID where toPG = pure . uuid+instance ToPG db (NetAddr IP) where toPG = pure . inet+instance ToPG db Char where toPG = pure . char_utf8+instance ToPG db Strict.Text where toPG = pure . text_strict+instance ToPG db Lazy.Text where toPG = pure . text_lazy+instance ToPG db String where+ toPG = pure . text_strict . Strict.Text.pack+instance ToPG db Strict.ByteString where toPG = pure . bytea_strict+instance ToPG db Lazy.ByteString where toPG = pure . bytea_lazy+instance ToPG db Day where toPG = pure . date+instance ToPG db TimeOfDay where toPG = pure . time_int+instance ToPG db (TimeOfDay, TimeZone) where toPG = pure . timetz_int+instance ToPG db LocalTime where toPG = pure . timestamp_int+instance ToPG db UTCTime where toPG = pure . timestamptz_int+instance ToPG db DiffTime where toPG = pure . interval_int+instance ToPG db Aeson.Value where toPG = pure . json_ast+instance Aeson.ToJSON x => ToPG db (Json x) where+ toPG = pure . json_bytes+ . Lazy.ByteString.toStrict . Aeson.encode . getJson+instance Aeson.ToJSON x => ToPG db (Jsonb x) where+ toPG = pure . jsonb_bytes+ . Lazy.ByteString.toStrict . Aeson.encode . getJsonb+instance (NullPG x ~ ty, ToArray db '[] ty x, OidOfNull db ty)+ => ToPG db (VarArray [x]) where+ toPG (VarArray arr) = do+ oid <- oidOfNull @db @ty+ let+ dims = [fromIntegral (length arr)]+ nulls = arrayNulls @db @'[] @ty @x+ payload <- dimArray foldM (arrayPayload @db @'[] @ty @x) arr+ return $ encodeArray 1 nulls oid dims payload+instance (NullPG x ~ ty, ToArray db '[] ty x, OidOfNull db ty)+ => ToPG db (VarArray (Vector x)) where+ toPG (VarArray arr) = do+ oid <- oidOfNull @db @ty+ let+ dims = [fromIntegral (length arr)]+ nulls = arrayNulls @db @'[] @ty @x+ payload <- dimArray foldM (arrayPayload @db @'[] @ty @x) arr+ return $ encodeArray 1 nulls oid dims payload+instance (ToArray db dims ty x, OidOfNull db ty)+ => ToPG db (FixArray x) where+ toPG (FixArray arr) = do+ oid <- oidOfNull @db @ty+ payload <- arrayPayload @db @dims @ty arr+ let+ dims = arrayDims @db @dims @ty @x+ nulls = arrayNulls @db @dims @ty @x+ ndims = fromIntegral (length dims)+ return $ encodeArray ndims nulls oid dims payload+instance+ ( SOP.IsEnumType x+ , SOP.HasDatatypeInfo x+ , LabelsPG x ~ labels+ ) => ToPG db (Enumerated x) where+ toPG =+ let+ gshowConstructor+ :: NP SOP.ConstructorInfo xss+ -> SOP.SOP SOP.I xss+ -> String+ gshowConstructor Nil _ = ""+ gshowConstructor (constructor :* _) (SOP.SOP (SOP.Z _)) =+ SOP.constructorName constructor+ gshowConstructor (_ :* constructors) (SOP.SOP (SOP.S xs)) =+ gshowConstructor constructors (SOP.SOP xs)+ in+ pure+ . text_strict+ . Strict.Text.pack+ . gshowConstructor+ (SOP.constructorInfo (SOP.datatypeInfo (SOP.Proxy @x)))+ . SOP.from+ . getEnumerated+instance+ ( SOP.SListI fields+ , SOP.IsRecord x xs+ , SOP.AllZip (ToField db) fields xs+ , SOP.All (OidOfField db) fields+ , RowPG x ~ fields+ ) => ToPG db (Composite x) where+ toPG (Composite x) = do+ let+ compositeSize+ = int4_int32+ $ fromIntegral+ $ SOP.lengthSList+ $ SOP.Proxy @xs+ each+ :: OidOfField db field+ => SOP.K (Maybe Encoding) field+ -> ReaderT (SOP.K LibPQ.Connection db) IO Encoding+ each (SOP.K field :: SOP.K (Maybe Encoding) field) = do+ oid <- getOid <$> oidOfField @db @field+ return $ int4_word32 oid <> maybe null4 sized field+ fields :: NP (SOP.K (Maybe Encoding)) fields <- hctransverse+ (SOP.Proxy @(ToField db)) (toField @db) (SOP.toRecord x)+ compositePayload <- hcfoldMapM+ (SOP.Proxy @(OidOfField db)) each fields+ return $ compositeSize <> compositePayload+instance ToPG db x => ToPG db (Range x) where+ toPG r = do+ payload <- case r of+ Empty -> return mempty+ NonEmpty lower upper -> (<>) <$> putBound lower <*> putBound upper+ return $ word8 (setFlags r 0) <> payload+ where+ putBound = \case+ Infinite -> return mempty+ Closed value -> sized <$> toPG @db value+ Open value -> sized <$> toPG @db value+ setFlags = \case+ Empty -> (`setBit` 0)+ NonEmpty lower upper ->+ setLowerFlags lower . setUpperFlags upper+ setLowerFlags = \case+ Infinite -> (`setBit` 3)+ Closed _ -> (`setBit` 1)+ Open _ -> id+ setUpperFlags = \case+ Infinite -> (`setBit` 4)+ Closed _ -> (`setBit` 2)+ Open _ -> id++-- | A `ToParam` constraint gives an encoding of a Haskell `Type` into+-- into the binary format of a PostgreSQL `NullType`.+-- You should not define instances for `ToParam`,+-- just use the provided instances.+class ToParam (db :: SchemasType) (ty :: NullType) (x :: Type) where+ toParam :: x -> ReaderT (SOP.K LibPQ.Connection db) IO (Maybe Encoding)+instance (ToPG db x, pg ~ PG x) => ToParam db ('NotNull pg) x where+ toParam = fmap Just . toPG @db+instance (ToPG db x, pg ~ PG x) => ToParam db ('Null pg) (Maybe x) where+ toParam = maybe (pure Nothing) (fmap Just . toPG @db)++-- | A `ToField` constraint lifts the `ToPG` parser+-- to an encoding of a @(Symbol, Type)@ to a @(Symbol, NullityType)@,+-- encoding `Null`s to `Maybe`s. You should not define instances for+-- `ToField`, just use the provided instances.+class ToField+ (db :: SchemasType)+ (field :: (Symbol, NullType))+ (x :: (Symbol, Type)) where+ toField :: SOP.P x+ -> ReaderT (SOP.K LibPQ.Connection db) IO (SOP.K (Maybe Encoding) field)+instance (fld0 ~ fld1, ToParam db ty x)+ => ToField db (fld0 ::: ty) (fld1 ::: x) where+ toField (SOP.P x) = SOP.K <$> toParam @db @ty x++-- | A `ToArray` constraint gives an encoding of a Haskell `Type`+-- into the binary format of a PostgreSQL fixed-length array.+-- You should not define instances for+-- `ToArray`, just use the provided instances.+class ToArray+ (db :: SchemasType)+ (dims :: [Nat])+ (ty :: NullType)+ (x :: Type) where+ arrayPayload :: x -> ReaderT (SOP.K LibPQ.Connection db) IO Encoding+ arrayDims :: [Int32]+ arrayNulls :: Bool+instance (ToPG db x, pg ~ PG x)+ => ToArray db '[] ('NotNull pg) x where+ arrayPayload = fmap sized . toPG @db @x+ arrayDims = []+ arrayNulls = False+instance (ToPG db x, pg ~ PG x)+ => ToArray db '[] ('Null pg) (Maybe x) where+ arrayPayload = maybe (pure null4) (fmap sized . toPG @db @x)+ arrayDims = []+ arrayNulls = True+instance+ ( SOP.IsProductType tuple xs+ , Length xs ~ dim+ , SOP.All ((~) x) xs+ , ToArray db dims ty x+ , KnownNat dim )+ => ToArray db (dim ': dims) ty tuple where+ arrayPayload+ = dimArray foldlNP (arrayPayload @db @dims @ty @x)+ . SOP.unZ . SOP.unSOP . SOP.from+ arrayDims+ = fromIntegral (natVal (SOP.Proxy @dim))+ : arrayDims @db @dims @ty @x+ arrayNulls = arrayNulls @db @dims @ty @x+foldlNP+ :: (SOP.All ((~) x) xs, Monad m)+ => (z -> x -> m z) -> z -> NP SOP.I xs -> m z+foldlNP f z = \case+ Nil -> pure z+ SOP.I x :* xs -> do+ z' <- f z x+ foldlNP f z' xs++{- |+`EncodeParams` describes an encoding of a Haskell `Type`+into a list of parameter `NullType`s.++>>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+>>> :{+let+ encode :: EncodeParams '[]+ '[ 'NotNull 'PGint2, 'NotNull ('PGchar 1), 'NotNull 'PGtext]+ (Int16, (Char, String))+ encode = fst .* fst.snd *. snd.snd+in runReaderT (runEncodeParams encode (1,('a',"foo"))) conn+:}+K (Just "\NUL\SOH") :* K (Just "a") :* K (Just "foo") :* Nil++>>> finish conn+-}+newtype EncodeParams+ (db :: SchemasType)+ (tys :: [NullType])+ (x :: Type) = EncodeParams+ { runEncodeParams :: x+ -> ReaderT (SOP.K LibPQ.Connection db) IO (NP (SOP.K (Maybe Encoding)) tys) }+instance Contravariant (EncodeParams db tys) where+ contramap f (EncodeParams g) = EncodeParams (g . f)++{- | Parameter encoding for `SOP.Generic` tuples and records.++>>> import qualified GHC.Generics as GHC+>>> import qualified Generics.SOP as SOP+>>> data Two = Two Int16 String deriving (GHC.Generic, SOP.Generic)+>>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+>>> :{+let+ encode :: EncodeParams '[] '[ 'NotNull 'PGint2, 'NotNull 'PGtext] Two+ encode = genericParams+in runReaderT (runEncodeParams encode (Two 2 "two")) conn+:}+K (Just "\NUL\STX") :* K (Just "two") :* Nil++>>> :{+let+ encode :: EncodeParams '[] '[ 'NotNull 'PGint2, 'NotNull 'PGtext] (Int16, String)+ encode = genericParams+in runReaderT (runEncodeParams encode (2, "two")) conn+:}+K (Just "\NUL\STX") :* K (Just "two") :* Nil++>>> finish conn+-}+genericParams :: forall db params x xs.+ ( SOP.IsProductType x xs+ , SOP.AllZip (ToParam db) params xs+ ) => EncodeParams db params x+genericParams = EncodeParams+ $ hctransverse (SOP.Proxy @(ToParam db)) encodeNullParam+ . SOP.unZ . SOP.unSOP . SOP.from+ where+ encodeNullParam+ :: forall ty y. ToParam db ty y+ => SOP.I y -> ReaderT (SOP.K LibPQ.Connection db) IO (SOP.K (Maybe Encoding) ty)+ encodeNullParam = fmap SOP.K . toParam @db @ty . SOP.unI++-- | Encode 0 parameters.+nilParams :: EncodeParams db '[] x+nilParams = EncodeParams $ \ _ -> pure Nil++{- | Cons a parameter encoding.++>>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+>>> :{+let+ encode :: EncodeParams '[]+ '[ 'Null 'PGint4, 'NotNull 'PGtext]+ (Maybe Int32, String)+ encode = fst .* snd .* nilParams+in runReaderT (runEncodeParams encode (Nothing, "foo")) conn+:}+K Nothing :* K (Just "foo") :* Nil++>>> finish conn+-}+(.*)+ :: forall db x0 ty x tys. (ToParam db ty x0)+ => (x -> x0) -- ^ head+ -> EncodeParams db tys x -- ^ tail+ -> EncodeParams db (ty ': tys) x+f .* EncodeParams params = EncodeParams $ \x ->+ (:*) <$> (SOP.K <$> toParam @db @ty (f x)) <*> params x+infixr 5 .*++{- | End a parameter encoding.++>>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+>>> :{+let+ encode :: EncodeParams '[]+ '[ 'Null 'PGint4, 'NotNull 'PGtext, 'NotNull ('PGchar 1)]+ (Maybe Int32, String, Char)+ encode = (\(x,_,_) -> x) .* (\(_,y,_) -> y) *. (\(_,_,z) -> z)+in runReaderT (runEncodeParams encode (Nothing, "foo", 'z')) conn+:}+K Nothing :* K (Just "foo") :* K (Just "z") :* Nil++>>> finish conn+-}+(*.)+ :: forall db x x0 ty0 x1 ty1+ . (ToParam db ty0 x0, ToParam db ty1 x1)+ => (x -> x0) -- ^ second to last+ -> (x -> x1) -- ^ last+ -> EncodeParams db '[ty0, ty1] x+f *. g = f .* g .* nilParams+infixl 8 *.++{- | Encode 1 parameter.++>>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+>>> :{+let+ encode :: EncodeParams '[] '[ 'NotNull 'PGint4] Int32+ encode = aParam+in runReaderT (runEncodeParams encode 1776) conn+:}+K (Just "\NUL\NUL\ACK\240") :* Nil++>>> finish conn+-}+aParam+ :: forall db x. ToParam db (NullPG x) x+ => EncodeParams db '[NullPG x] x+aParam = EncodeParams $+ fmap (\param -> SOP.K param :* Nil) . toParam @db @(NullPG x)++{- | Append parameter encodings.++>>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+>>> :{+let+ encode :: EncodeParams '[]+ '[ 'NotNull 'PGint4, 'NotNull 'PGint2]+ (Int32, Int16)+ encode = contramap fst aParam `appendParams` contramap snd aParam+in runReaderT (runEncodeParams encode (1776, 2)) conn+:}+K (Just "\NUL\NUL\ACK\240") :* K (Just "\NUL\STX") :* Nil++>>> finish conn+-}+appendParams+ :: EncodeParams db params0 x -- ^ left+ -> EncodeParams db params1 x -- ^ right+ -> EncodeParams db (Join params0 params1) x+appendParams encode0 encode1 = EncodeParams $ \x -> also+ <$> runEncodeParams encode1 x+ <*> runEncodeParams encode0 x++getOid :: LibPQ.Oid -> Word32+getOid (LibPQ.Oid (CUInt oid)) = oid++encodeArray :: Int32 -> Bool -> LibPQ.Oid -> [Int32] -> Encoding -> Encoding+encodeArray ndim nulls oid dimensions payload = mconcat+ [ int4_int32 ndim+ , if nulls then true4 else false4+ , int4_word32 (getOid oid)+ , foldMap (\dimension -> int4_int32 dimension <> true4) dimensions+ , payload ]++dimArray+ :: Functor m+ => (forall b. (b -> a -> m b) -> b -> c -> m b)+ -> (a -> m Encoding) -> c -> m Encoding+dimArray folder elementArray = folder step mempty+ where+ step builder element = (builder <>) <$> elementArray element++null4, true4, false4 :: Encoding+null4 = int4_int32 (-1)+true4 = int4_word32 1+false4 = int4_word32 0++sized :: Encoding -> Encoding+sized bs = int4_int32 (fromIntegral (builderLength bs)) <> bs++hctransverse+ :: (SOP.AllZip c ys xs, Applicative m)+ => SOP.Proxy c+ -> (forall y x. c y x => f x -> m (g y))+ -> NP f xs -> m (NP g ys)+hctransverse c f = \case+ Nil -> pure Nil+ x :* xs -> (:*) <$> f x <*> hctransverse c f xs++hcfoldMapM+ :: (Monoid r, Applicative m, SOP.All c xs)+ => SOP.Proxy c+ -> (forall x. c x => f x -> m r)+ -> NP f xs -> m r+hcfoldMapM c f = \case+ Nil -> pure mempty+ x :* xs -> (<>) <$> f x <*> hcfoldMapM c f xs
+ src/Squeal/PostgreSQL/Session/Exception.hs view
@@ -0,0 +1,96 @@+{-|+Module: Squeal.PostgreSQL.Session.Exception+Description: exceptions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++exceptions+-}++{-# LANGUAGE+ OverloadedStrings+ , PatternSynonyms+#-}++module Squeal.PostgreSQL.Session.Exception+ ( SquealException (..)+ , pattern UniqueViolation+ , pattern CheckViolation+ , pattern SerializationFailure+ , SQLState (..)+ , LibPQ.ExecStatus (..)+ , catchSqueal+ , handleSqueal+ , trySqueal+ , throwSqueal+ ) where++import Control.Exception (Exception)+import Data.ByteString (ByteString)+import Data.Text (Text)+import UnliftIO (MonadUnliftIO (..), catch, handle, try, throwIO)++import qualified Database.PostgreSQL.LibPQ as LibPQ++-- $setup+-- >>> import Squeal.PostgreSQL++-- | the state of LibPQ+data SQLState = SQLState+ { sqlExecStatus :: LibPQ.ExecStatus+ , sqlStateCode :: ByteString+ -- ^ https://www.postgresql.org/docs/current/static/errcodes-appendix.html+ , sqlErrorMessage :: ByteString+ } deriving (Eq, Show)++-- | `Exception`s that can be thrown by Squeal.+data SquealException+ = SQLException SQLState+ -- ^ SQL exception state+ | ConnectionException Text+ -- ^ `Database.PostgreSQL.LibPQ` function connection exception+ | DecodingException Text Text+ -- ^ decoding exception function and error message+ | ColumnsException Text LibPQ.Column+ -- ^ unexpected number of columns+ | RowsException Text LibPQ.Row LibPQ.Row+ -- ^ too few rows, expected at least and actual number of rows+ deriving (Eq, Show)+instance Exception SquealException++-- | A pattern for unique violation exceptions.+pattern UniqueViolation :: ByteString -> SquealException+pattern UniqueViolation msg =+ SQLException (SQLState LibPQ.FatalError "23505" msg)+-- | A pattern for check constraint violation exceptions.+pattern CheckViolation :: ByteString -> SquealException+pattern CheckViolation msg =+ SQLException (SQLState LibPQ.FatalError "23514" msg)+-- | A pattern for serialization failure exceptions.+pattern SerializationFailure :: ByteString -> SquealException+pattern SerializationFailure msg =+ SQLException (SQLState LibPQ.FatalError "40001" msg)++-- | Catch `SquealException`s.+catchSqueal+ :: MonadUnliftIO io+ => io a+ -> (SquealException -> io a) -- ^ handler+ -> io a+catchSqueal = catch++-- | Handle `SquealException`s.+handleSqueal+ :: MonadUnliftIO io+ => (SquealException -> io a) -- ^ handler+ -> io a -> io a+handleSqueal = handle++-- | `Either` return a `SquealException` or a result.+trySqueal :: MonadUnliftIO io => io a -> io (Either SquealException a)+trySqueal = try++-- | Throw `SquealException`s.+throwSqueal :: MonadUnliftIO io => SquealException -> io a+throwSqueal = throwIO
+ src/Squeal/PostgreSQL/Session/Indexed.hs view
@@ -0,0 +1,126 @@+{-|+Module: Squeal.PostgreSQL.Session.Indexed+Description: indexed session monad+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++`Squeal.PostgreSQL.Indexed` provides an indexed monad transformer+class and a class extending it to run `Definition`s.+-}++{-# LANGUAGE+ DataKinds+ , DefaultSignatures+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , PolyKinds+ , MultiParamTypeClasses+ , QuantifiedConstraints+ , RankNTypes+ , TypeApplications+ , TypeFamilies+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session.Indexed+ ( IndexedMonadTrans (..)+ , Indexed (..)+ , IndexedMonadTransPQ (..)+ , indexedDefine+ ) where++import Control.Category (Category (..))+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans+import Data.Function ((&))+import Prelude hiding (id, (.))++import Squeal.PostgreSQL.Definition++{- | An [Atkey indexed monad]+(https://bentnib.org/paramnotions-jfp.pdf)+is a `Functor` [enriched category]+(https://ncatlab.org/nlab/show/enriched+category).+An indexed monad transformer transforms a `Monad` into an indexed monad,+and is a monad transformer when its source and target are the same,+enabling use of standard @do@ notation for endo-index operations.+-}+class+ ( forall i j m. Monad m => Functor (t i j m)+ , forall i j m. (i ~ j, Monad m) => Monad (t i j m)+ , forall i j. i ~ j => MonadTrans (t i j)+ ) => IndexedMonadTrans t where++ {-# MINIMAL pqJoin | pqBind #-}++ -- | indexed analog of `<*>`+ pqAp+ :: Monad m+ => t i j m (x -> y)+ -> t j k m x+ -> t i k m y+ pqAp tf tx = pqBind (<$> tx) tf++ -- | indexed analog of `join`+ pqJoin+ :: Monad m+ => t i j m (t j k m y)+ -> t i k m y+ pqJoin t = t & pqBind id++ -- | indexed analog of `=<<`+ pqBind+ :: Monad m+ => (x -> t j k m y)+ -> t i j m x+ -> t i k m y+ pqBind f t = pqJoin (f <$> t)++ -- | indexed analog of flipped `>>`+ pqThen+ :: Monad m+ => t j k m y+ -> t i j m x+ -> t i k m y+ pqThen pq2 pq1 = pq1 & pqBind (\ _ -> pq2)++ -- | indexed analog of `<=<`+ pqAndThen+ :: Monad m+ => (y -> t j k m z)+ -> (x -> t i j m y)+ -> x -> t i k m z+ pqAndThen g f x = pqBind g (f x)++{- | `Indexed` reshuffles the type parameters of an `IndexedMonadTrans`,+exposing its `Category` instance.-}+newtype Indexed t m r i j = Indexed {runIndexed :: t i j m r}+instance+ ( IndexedMonadTrans t+ , Monad m+ , Monoid r+ ) => Category (Indexed t m r) where+ id = Indexed (pure mempty)+ Indexed g . Indexed f = Indexed $ pqAp (fmap (<>) f) g++{- | `IndexedMonadTransPQ` is a class for indexed monad transformers+that support running `Definition`s using `define` which acts functorially in effect.++* @define id = return ()@+* @define (statement1 >>> statement2) = define statement1 & pqThen (define statement2)@+-}+class IndexedMonadTrans pq => IndexedMonadTransPQ pq where+ define :: MonadIO io => Definition db0 db1 -> pq db0 db1 io ()++{- | Run a pure SQL `Definition` functorially in effect++* @indexedDefine id = id@+* @indexedDefine (def1 >>> def2) = indexedDefine def1 >>> indexedDefine def2@+-}+indexedDefine+ :: (IndexedMonadTransPQ pq, MonadIO io)+ => Definition db0 db1 -> Indexed pq io () db0 db1+indexedDefine = Indexed . define
+ src/Squeal/PostgreSQL/Session/Migration.hs view
@@ -0,0 +1,458 @@+{-|+Module: Squeal.PostgreSQL.Session.Migration+Description: migrations+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++This module defines a `Migration` type to safely+change the schema of your database over time. Let's see an example!++First turn on some extensions.++>>> :set -XDataKinds -XOverloadedLabels+>>> :set -XOverloadedStrings -XFlexibleContexts -XTypeOperators++Next, let's define our `TableType`s.++>>> :{+type UsersTable =+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext+ ]+:}++>>> :{+type EmailsTable =+ '[ "pk_emails" ::: 'PrimaryKey '["id"]+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]+ ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4+ , "email" ::: 'NoDef :=> 'Null 'PGtext+ ]+:}++Now we can define some `Migration`s to make our tables.++`Migration`s are parameterized giving the option of a++* pure one-way `Migration` `Definition`+* impure one-way `Migration` @(@`Indexed` `PQ` `IO`@)@+* pure reversible `Migration` @(@`IsoQ` `Definition`@)@+* impure reversible `Migration` @(@`IsoQ` @(@`Indexed` `PQ` `IO`@)@@)@++For this example, we'll use pure reversible `Migration`s.++>>> :{+let+ makeUsers :: Migration (IsoQ Definition)+ '["public" ::: '[]]+ '["public" ::: '["users" ::: 'Table UsersTable]]+ makeUsers = Migration "make users table" IsoQ+ { up = createTable #users+ ( serial `as` #id :*+ notNullable text `as` #name )+ ( primaryKey #id `as` #pk_users )+ , down = dropTable #users+ }+:}++>>> :{+let+ makeEmails :: Migration (IsoQ Definition)+ '["public" ::: '["users" ::: 'Table UsersTable]]+ '["public" ::: '["users" ::: 'Table UsersTable, "emails" ::: 'Table EmailsTable]]+ makeEmails = Migration "make emails table" IsoQ+ { up = createTable #emails+ ( serial `as` #id :*+ notNullable int `as` #user_id :*+ nullable text `as` #email )+ ( primaryKey #id `as` #pk_emails :*+ foreignKey #user_id #users #id+ OnDeleteCascade OnUpdateCascade `as` #fk_user_id )+ , down = dropTable #emails+ }+:}++Now that we have a couple migrations we can chain them together into a `Path`.++>>> let migrations = makeUsers :>> makeEmails :>> Done++Now run the migrations.++>>> import Control.Monad.IO.Class+>>> :{+withConnection "host=localhost port=5432 dbname=exampledb" $+ manipulate_ (UnsafeManipulation "SET client_min_messages TO WARNING;")+ -- suppress notices+ & pqThen (liftIO (putStrLn "Migrate"))+ & pqThen (migrateUp migrations)+ & pqThen (liftIO (putStrLn "Rollback"))+ & pqThen (migrateDown migrations)+:}+Migrate+Rollback++We can also create a simple executable using `mainMigrateIso`.++>>> let main = mainMigrateIso "host=localhost port=5432 dbname=exampledb" migrations++>>> withArgs [] main+Invalid command: "". Use:+migrate to run all available migrations+rollback to rollback all available migrations+status to display migrations run and migrations left to run++>>> withArgs ["status"] main+Migrations already run:+ None+Migrations left to run:+ - make users table+ - make emails table++>>> withArgs ["migrate"] main+Migrations already run:+ - make users table+ - make emails table+Migrations left to run:+ None++>>> withArgs ["rollback"] main+Migrations already run:+ None+Migrations left to run:+ - make users table+ - make emails table++In addition to enabling `Migration`s using pure SQL `Definition`s for+the `up` and `down` migrations, you can also perform impure `IO` actions+by using a `Migration`s over the `Indexed` `PQ` `IO` category.+-}++{-# LANGUAGE+ DataKinds+ , DeriveGeneric+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , PolyKinds+ , QuantifiedConstraints+ , RankNTypes+ , TypeApplications+ , TypeOperators+#-}++module Squeal.PostgreSQL.Session.Migration+ ( -- * Migration+ Migration (..)+ , Migratory (..)+ , migrate+ , migrateUp+ , migrateDown+ , MigrationsTable+ -- * Executable+ , mainMigrate+ , mainMigrateIso+ -- * Re-export+ , IsoQ (..)+ ) where++import Control.Category+import Control.Category.Free+import Control.Monad+import Data.ByteString (ByteString)+import Data.Foldable (traverse_)+import Data.Function ((&))+import Data.List ((\\))+import Data.Quiver+import Data.Quiver.Functor+import Data.Text (Text)+import Data.Time (UTCTime)+import Prelude hiding ((.), id)+import System.Environment+import UnliftIO (MonadIO (..))++import qualified Data.Text.IO as Text (putStrLn)+import qualified Generics.SOP as SOP+import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Definition+import Squeal.PostgreSQL.Definition.Constraint+import Squeal.PostgreSQL.Definition.Table+import Squeal.PostgreSQL.Expression.Comparison+import Squeal.PostgreSQL.Expression.Default+import Squeal.PostgreSQL.Expression.Parameter+import Squeal.PostgreSQL.Expression.Time+import Squeal.PostgreSQL.Expression.Type+import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Manipulation.Delete+import Squeal.PostgreSQL.Manipulation.Insert+import Squeal.PostgreSQL.Session+import Squeal.PostgreSQL.Session.Decode+import Squeal.PostgreSQL.Session.Encode+import Squeal.PostgreSQL.Session.Indexed+import Squeal.PostgreSQL.Session.Monad+import Squeal.PostgreSQL.Session.Result+import Squeal.PostgreSQL.Session.Statement+import Squeal.PostgreSQL.Session.Transaction+import Squeal.PostgreSQL.Query.From+import Squeal.PostgreSQL.Query.Select+import Squeal.PostgreSQL.Query.Table+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Type.Schema++-- | A `Migration` consists of a name and a migration definition.+data Migration def db0 db1 = Migration+ { name :: Text -- ^ The `name` of a `Migration`.+ -- Each `name` in a `Migration` should be unique.+ , migration :: def db0 db1 -- ^ The migration of a `Migration`.+ } deriving (GHC.Generic)+instance QFunctor Migration where+ qmap f (Migration n i) = Migration n (f i)++{- |+A `Migratory` `Category` can run or+possibly rewind a `Path` of `Migration`s.+-}+class (Category def, Category run) => Migratory def run | def -> run where+ {- | Run a `Path` of `Migration`s.-}+ runMigrations :: Path (Migration def) db0 db1 -> run db0 db1+-- | impure migrations+instance Migratory (Indexed PQ IO ()) (Indexed PQ IO ()) where+ runMigrations path = Indexed . unsafePQ . transactionally_ $ do+ define createMigrations+ qtoMonoid upMigration path+ where+ upMigration step = do+ executed <- do+ result <- executeParams selectMigration (name step)+ ntuples (result :: Result UTCTime)+ unless (executed == 1) $ do+ _ <- unsafePQ . runIndexed $ migration step+ executeParams_ insertMigration (name step)+-- | pure migrations+instance Migratory Definition (Indexed PQ IO ()) where+ runMigrations = runMigrations . qmap (qmap ixDefine)+-- | impure rewinds+instance Migratory (OpQ (Indexed PQ IO ())) (OpQ (Indexed PQ IO ())) where+ runMigrations path = OpQ . Indexed . unsafePQ . transactionally_ $ do+ define createMigrations+ qtoMonoid @FoldPath downMigration (reversePath path)+ where+ downMigration (OpQ step) = do+ executed <- do+ result <- executeParams selectMigration (name step)+ ntuples (result :: Result UTCTime)+ unless (executed == 0) $ do+ _ <- unsafePQ . runIndexed . getOpQ $ migration step+ executeParams_ deleteMigration (name step)+-- | pure rewinds+instance Migratory (OpQ Definition) (OpQ (Indexed PQ IO ())) where+ runMigrations = runMigrations . qmap (qmap (qmap ixDefine))+-- | impure rewindable migrations+instance Migratory+ (IsoQ (Indexed PQ IO ()))+ (IsoQ (Indexed PQ IO ())) where+ runMigrations path = IsoQ+ (runMigrations (qmap (qmap up) path))+ (getOpQ (runMigrations (qmap (qmap (OpQ . down)) path)))+-- | pure rewindable migrations+instance Migratory (IsoQ Definition) (IsoQ (Indexed PQ IO ())) where+ runMigrations = runMigrations . qmap (qmap (qmap ixDefine))++unsafePQ :: (Functor m) => PQ db0 db1 m x -> PQ db0' db1' m x+unsafePQ (PQ pq) = PQ $ fmap (SOP.K . SOP.unK) . pq . SOP.K . SOP.unK++-- | Run migrations.+migrate+ :: Migratory def (Indexed PQ IO ())+ => Path (Migration def) db0 db1+ -> PQ db0 db1 IO ()+migrate = runIndexed . runMigrations++-- | Run rewindable migrations.+migrateUp+ :: Migratory def (IsoQ (Indexed PQ IO ()))+ => Path (Migration def) db0 db1+ -> PQ db0 db1 IO ()+migrateUp = runIndexed . up . runMigrations++-- | Rewind migrations.+migrateDown+ :: Migratory def (IsoQ (Indexed PQ IO ()))+ => Path (Migration def) db0 db1+ -> PQ db1 db0 IO ()+migrateDown = runIndexed . down . runMigrations++ixDefine :: Definition db0 db1 -> Indexed PQ IO () db0 db1+ixDefine = indexedDefine++-- | The `TableType` for a Squeal migration.+type MigrationsTable =+ '[ "migrations_unique_name" ::: 'Unique '["name"]] :=>+ '[ "name" ::: 'NoDef :=> 'NotNull 'PGtext+ , "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz+ ]++data MigrationRow =+ MigrationRow { migrationName :: Text+ , migrationTime :: UTCTime }+ deriving (GHC.Generic, Show)++instance SOP.Generic MigrationRow+instance SOP.HasDatatypeInfo MigrationRow++type MigrationsSchema = '["schema_migrations" ::: 'Table MigrationsTable]+type MigrationsSchemas = Public MigrationsSchema++-- | Creates a `MigrationsTable` if it does not already exist.+createMigrations :: Definition MigrationsSchemas MigrationsSchemas+createMigrations =+ createTableIfNotExists #schema_migrations+ ( (text & notNullable) `as` #name :*+ (timestampWithTimeZone & notNullable & default_ currentTimestamp)+ `as` #executed_at )+ ( unique #name `as` #migrations_unique_name )++-- | Inserts a `Migration` into the `MigrationsTable`, returning+-- the time at which it was inserted.+insertMigration :: Statement MigrationsSchemas Text ()+insertMigration = Manipulation aParam genericRow $+ insertInto_ #schema_migrations $+ Values_ (Set (param @1) `as` #name :* Default `as` #executed_at)++-- | Deletes a `Migration` from the `MigrationsTable`, returning+-- the time at which it was inserted.+deleteMigration :: Statement MigrationsSchemas Text ()+deleteMigration = Manipulation aParam genericRow $+ deleteFrom_ #schema_migrations (#name .== param @1)++-- | Selects a `Migration` from the `MigrationsTable`, returning+-- the time at which it was inserted.+selectMigration :: Statement MigrationsSchemas Text UTCTime+selectMigration = Query aParam #executed_at $+ select_ #executed_at+ $ from (table (#schema_migrations))+ & where_ (#name .== param @1)++selectMigrations :: Statement MigrationsSchemas () MigrationRow+selectMigrations = query $+ select_ (#name `as` #migrationName :* #executed_at `as` #migrationTime)+ (from (table #schema_migrations))++{- | `mainMigrate` creates a simple executable+from a connection string and a `Path` of `Migration`s. -}+mainMigrate+ :: Migratory p (Indexed PQ IO ())+ => ByteString+ -- ^ connection string+ -> Path (Migration p) db0 db1+ -- ^ migrations+ -> IO ()+mainMigrate connectTo migrations = do+ command <- getArgs+ performCommand command++ where++ performCommand :: [String] -> IO ()+ performCommand = \case+ ["status"] -> withConnection connectTo $+ suppressNotices >> migrateStatus+ ["migrate"] -> withConnection connectTo $+ suppressNotices+ & pqThen (runIndexed (runMigrations migrations))+ & pqThen migrateStatus+ args -> displayUsage args++ migrateStatus :: PQ schema schema IO ()+ migrateStatus = unsafePQ $ do+ runNames <- getRunMigrationNames+ let names = qtoList name migrations+ unrunNames = names \\ runNames+ liftIO $ displayRunned runNames >> displayUnrunned unrunNames++ suppressNotices :: PQ schema schema IO ()+ suppressNotices = manipulate_ $+ UnsafeManipulation "SET client_min_messages TO WARNING;"++ displayUsage :: [String] -> IO ()+ displayUsage args = do+ putStrLn $ "Invalid command: \"" <> unwords args <> "\". Use:"+ putStrLn "migrate to run all available migrations"+ putStrLn "rollback to rollback all available migrations"++{- | `mainMigrateIso` creates a simple executable+from a connection string and a `Path` of `Migration` `IsoQ`s. -}+mainMigrateIso+ :: Migratory (IsoQ def) (IsoQ (Indexed PQ IO ()))+ => ByteString+ -- ^ connection string+ -> Path (Migration (IsoQ def)) db0 db1+ -- ^ migrations+ -> IO ()+mainMigrateIso connectTo migrations = performCommand =<< getArgs++ where++ performCommand :: [String] -> IO ()+ performCommand = \case+ ["status"] -> withConnection connectTo $+ suppressNotices >> migrateStatus+ ["migrate"] -> withConnection connectTo $+ suppressNotices+ & pqThen (migrateUp migrations)+ & pqThen migrateStatus+ ["rollback"] -> withConnection connectTo $+ suppressNotices+ & pqThen (migrateDown migrations)+ & pqThen migrateStatus+ args -> displayUsage args++ migrateStatus :: PQ schema schema IO ()+ migrateStatus = unsafePQ $ do+ runNames <- getRunMigrationNames+ let names = qtoList name migrations+ unrunNames = names \\ runNames+ liftIO $ displayRunned runNames >> displayUnrunned unrunNames++ suppressNotices :: PQ schema schema IO ()+ suppressNotices = manipulate_ $+ UnsafeManipulation "SET client_min_messages TO WARNING;"++ displayUsage :: [String] -> IO ()+ displayUsage args = do+ putStrLn $ "Invalid command: \"" <> unwords args <> "\". Use:"+ putStrLn "migrate to run all available migrations"+ putStrLn "rollback to rollback all available migrations"+ putStrLn "status to display migrations run and migrations left to run"++getRunMigrationNames :: PQ db0 db0 IO [Text]+getRunMigrationNames =+ fmap migrationName <$>+ (unsafePQ (define createMigrations+ & pqThen (execute selectMigrations)) >>= getRows)++displayListOfNames :: [Text] -> IO ()+displayListOfNames [] = Text.putStrLn " None"+displayListOfNames xs =+ let singleName n = Text.putStrLn $ " - " <> n+ in traverse_ singleName xs++displayUnrunned :: [Text] -> IO ()+displayUnrunned unrunned =+ Text.putStrLn "Migrations left to run:"+ >> displayListOfNames unrunned++displayRunned :: [Text] -> IO ()+displayRunned runned =+ Text.putStrLn "Migrations already run:"+ >> displayListOfNames runned
+ src/Squeal/PostgreSQL/Session/Monad.hs view
@@ -0,0 +1,267 @@+{-|+Module: Squeal.PostgreSQL.Session.Monad+Description: session monad+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Run `Squeal.PostgreSQL.Session.Statement`s in the mtl-style+typeclass `MonadPQ`.+-}+{-# LANGUAGE+ DataKinds+ , DefaultSignatures+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GADTs+ , PolyKinds+ , MultiParamTypeClasses+ , QuantifiedConstraints+ , RankNTypes+ , TypeApplications+ , TypeFamilies+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session.Monad where++import Control.Category (Category (..))+import Control.Monad+import Control.Monad.Morph+import Prelude hiding (id, (.))++import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP++import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Session.Decode+import Squeal.PostgreSQL.Session.Result+import Squeal.PostgreSQL.Session.Statement+import Squeal.PostgreSQL.Query++-- For `MonadPQ` transformer instances+import Control.Monad.Trans.Cont+import Control.Monad.Trans.Identity+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Reader+import qualified Control.Monad.Trans.State.Lazy as Lazy+import qualified Control.Monad.Trans.State.Strict as Strict+import qualified Control.Monad.Trans.Writer.Lazy as Lazy+import qualified Control.Monad.Trans.Writer.Strict as Strict+import qualified Control.Monad.Trans.RWS.Lazy as Lazy+import qualified Control.Monad.Trans.RWS.Strict as Strict++{- | `MonadPQ` is an @mtl@ style constraint, similar to+`Control.Monad.State.Class.MonadState`, for using `Database.PostgreSQL.LibPQ`+to run `Statement`s.+-}+class Monad pq => MonadPQ db pq | pq -> db where++ {- |+ `executeParams` runs a `Statement`.+ It calls `LibPQ.execParams` and doesn't afraid of anything.+ -}+ executeParams :: Statement db x y -> x -> pq (Result y)+ default executeParams+ :: (MonadTrans t, MonadPQ db m, pq ~ t m)+ => Statement db x y -> x -> pq (Result y)+ executeParams statement params = lift $ executeParams statement params++ {- |+ `executeParams_` runs a returning-free `Statement`.+ It calls `LibPQ.execParams` and doesn't afraid of anything.+ -}+ executeParams_ :: Statement db x () -> x -> pq ()+ executeParams_ statement params = void $ executeParams statement params++ {- |+ `execute` runs a parameter-free `Statement`.+ -}+ execute :: Statement db () y -> pq (Result y)+ execute statement = executeParams statement ()++ {- |+ `execute_` runs a parameter-free, returning-free `Statement`.+ -}+ execute_ :: Statement db () () -> pq ()+ execute_ = void . execute++ {- |+ `executePrepared` runs a `Statement` on a `Traversable`+ container by first preparing the statement, then running the prepared+ statement on each element.+ -}+ executePrepared+ :: Traversable list+ => Statement db x y -> list x -> pq (list (Result y))+ default executePrepared+ :: (MonadTrans t, MonadPQ db m, pq ~ t m)+ => Traversable list+ => Statement db x y -> list x -> pq (list (Result y))+ executePrepared statement x = lift $ executePrepared statement x++ {- |+ `executePrepared_` runs a returning-free `Statement` on a `Foldable`+ container by first preparing the statement, then running the prepared+ statement on each element.+ -}+ executePrepared_+ :: Foldable list+ => Statement db x () -> list x -> pq ()+ default executePrepared_+ :: (MonadTrans t, MonadPQ db m, pq ~ t m)+ => Foldable list+ => Statement db x () -> list x -> pq ()+ executePrepared_ statement x = lift $ executePrepared_ statement x++{- |+`manipulateParams` runs a `Squeal.PostgreSQL.Manipulation.Manipulation`.+-}+manipulateParams ::+ ( MonadPQ db pq+ , GenericParams db params x xs+ , GenericRow row y ys+ ) => Manipulation '[] db params row+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom`, and friends+ -> x -> pq (Result y)+manipulateParams = executeParams . manipulation++{- |+`manipulateParams_` runs a `Squeal.PostgreSQL.Manipulation.Manipulation`,+for a returning-free statement.+-}+manipulateParams_ ::+ ( MonadPQ db pq+ , GenericParams db params x xs+ ) => Manipulation '[] db params '[]+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto_`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update_`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom_`, and friends+ -> x -> pq ()+manipulateParams_ = executeParams_ . manipulation++{- |+`manipulate` runs a `Squeal.PostgreSQL.Manipulation.Manipulation`,+for a parameter-free statement.+-}+manipulate+ :: (MonadPQ db pq, GenericRow row y ys)+ => Manipulation '[] db '[] row+ -> pq (Result y)+manipulate = execute . manipulation++{- |+`manipulate_` runs a `Squeal.PostgreSQL.Manipulation.Manipulation`,+for a returning-free, parameter-free statement.+-}+manipulate_+ :: MonadPQ db pq+ => Manipulation '[] db '[] '[]+ -> pq ()+manipulate_ = execute_ . manipulation++{- |+`runQueryParams` runs a `Squeal.PostgreSQL.Query.Query`.+-}+runQueryParams ::+ ( MonadPQ db pq+ , GenericParams db params x xs+ , SOP.IsRecord y ys+ , SOP.AllZip FromField row ys+ ) => Query '[] '[] db params row+ -- ^ `Squeal.PostgreSQL.Query.Select.select` and friends+ -> x -> pq (Result y)+runQueryParams = executeParams . query++{- |+`runQuery` runs a `Squeal.PostgreSQL.Query.Query`,+for a parameter-free statement.+-}+runQuery+ :: (MonadPQ db pq, SOP.IsRecord y ys, SOP.AllZip FromField row ys)+ => Query '[] '[] db '[] row+ -- ^ `Squeal.PostgreSQL.Query.Select.select` and friends+ -> pq (Result y)+runQuery = execute . query++{- |+`traversePrepared` runs a `Squeal.PostgreSQL.Manipulation.Manipulation`+on a `Traversable` container by first preparing the statement,+then running the prepared statement on each element.+-}+traversePrepared+ :: ( MonadPQ db pq+ , GenericParams db params x xs+ , Traversable list+ , SOP.IsRecord y ys+ , SOP.AllZip FromField row ys )+ => Manipulation '[] db params row+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom`, and friends+ -> list x -> pq (list (Result y))+traversePrepared = executePrepared . manipulation++{- |+`forPrepared` is a flipped `traversePrepared`+-}+forPrepared+ :: ( MonadPQ db pq+ , GenericParams db params x xs+ , Traversable list+ , SOP.IsRecord y ys+ , SOP.AllZip FromField row ys )+ => list x+ -> Manipulation '[] db params row+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom`, and friends+ -> pq (list (Result y))+forPrepared = flip traversePrepared++{- |+`traversePrepared` runs a returning-free+`Squeal.PostgreSQL.Manipulation.Manipulation` on a `Foldable`+container by first preparing the statement, then running the prepared+statement on each element.+-}+traversePrepared_+ :: ( MonadPQ db pq+ , GenericParams db params x xs+ , Foldable list )+ => Manipulation '[] db params '[]+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto_`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update_`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom_`, and friends+ -> list x -> pq ()+traversePrepared_ = executePrepared_ . manipulation++{- |+`forPrepared_` is a flipped `traversePrepared_`+-}+forPrepared_+ :: ( MonadPQ db pq+ , GenericParams db params x xs+ , Foldable list )+ => list x+ -> Manipulation '[] db params '[]+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto_`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update_`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom_`, and friends+ -> pq ()+forPrepared_ = flip traversePrepared_++instance MonadPQ db m => MonadPQ db (IdentityT m)+instance MonadPQ db m => MonadPQ db (ReaderT r m)+instance MonadPQ db m => MonadPQ db (Strict.StateT s m)+instance MonadPQ db m => MonadPQ db (Lazy.StateT s m)+instance (Monoid w, MonadPQ db m) => MonadPQ db (Strict.WriterT w m)+instance (Monoid w, MonadPQ db m) => MonadPQ db (Lazy.WriterT w m)+instance MonadPQ db m => MonadPQ db (MaybeT m)+instance MonadPQ db m => MonadPQ db (ExceptT e m)+instance (Monoid w, MonadPQ db m) => MonadPQ db (Strict.RWST r w s m)+instance (Monoid w, MonadPQ db m) => MonadPQ db (Lazy.RWST r w s m)+instance MonadPQ db m => MonadPQ db (ContT r m)
+ src/Squeal/PostgreSQL/Session/Oid.hs view
@@ -0,0 +1,221 @@+{-|+Module: Squeal.PostgreSQL.Session.Oid+Description: object identifiers+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Object identifiers are used internally by PostgreSQL as+primary keys. They are needed to correctly encode+statement parameters.+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , DataKinds+ , FlexibleContexts+ , FlexibleInstances+ , MultiParamTypeClasses+ , OverloadedStrings+ , PolyKinds+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session.Oid+ ( -- * Oids+ LibPQ.Oid+ , OidOf (..)+ , OidOfArray (..)+ , OidOfNull (..)+ , OidOfField (..)+ ) where++import Control.Monad.Reader+import Data.String+import GHC.TypeLits+import UnliftIO (throwIO)+import PostgreSQL.Binary.Decoding (valueParser, int)++import qualified Data.ByteString as ByteString+import qualified Database.PostgreSQL.LibPQ as LibPQ+import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Session.Exception+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL++-- | The `LibPQ.Oid` of a `PGType`+--+-- >>> :set -XTypeApplications+-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"+-- >>> runReaderT (oidOf @'[] @'PGbool) conn+-- Oid 16+--+-- >>> finish conn+class OidOf (db :: SchemasType) (pg :: PGType) where+ oidOf :: ReaderT (SOP.K LibPQ.Connection db) IO LibPQ.Oid+-- | The `LibPQ.Oid` of an array+class OidOfArray (db :: SchemasType) (pg :: PGType) where+ oidOfArray :: ReaderT (SOP.K LibPQ.Connection db) IO LibPQ.Oid+instance OidOfArray db pg => OidOf db ('PGvararray (null pg)) where+ oidOf = oidOfArray @db @pg+instance OidOfArray db pg => OidOf db ('PGfixarray dims (null pg)) where+ oidOf = oidOfArray @db @pg+-- | The `LibPQ.Oid` of a `NullType`+class OidOfNull (db :: SchemasType) (ty :: NullType) where+ oidOfNull :: ReaderT (SOP.K LibPQ.Connection db) IO LibPQ.Oid+instance OidOf db pg => OidOfNull db (null pg) where+ oidOfNull = oidOf @db @pg+-- | The `LibPQ.Oid` of a field+class OidOfField (db :: SchemasType) (field :: (Symbol, NullType)) where+ oidOfField :: ReaderT (SOP.K LibPQ.Connection db) IO LibPQ.Oid+instance OidOfNull db ty => OidOfField db (fld ::: ty) where+ oidOfField = oidOfNull @db @ty++instance OidOf db 'PGbool where oidOf = pure $ LibPQ.Oid 16+instance OidOfArray db 'PGbool where oidOfArray = pure $ LibPQ.Oid 1000+instance OidOf db 'PGint2 where oidOf = pure $ LibPQ.Oid 21+instance OidOfArray db 'PGint2 where oidOfArray = pure $ LibPQ.Oid 1005+instance OidOf db 'PGint4 where oidOf = pure $ LibPQ.Oid 23+instance OidOfArray db 'PGint4 where oidOfArray = pure $ LibPQ.Oid 1007+instance OidOf db 'PGint8 where oidOf = pure $ LibPQ.Oid 20+instance OidOfArray db 'PGint8 where oidOfArray = pure $ LibPQ.Oid 1016+instance OidOf db 'PGnumeric where oidOf = pure $ LibPQ.Oid 1700+instance OidOfArray db 'PGnumeric where oidOfArray = pure $ LibPQ.Oid 1231+instance OidOf db 'PGfloat4 where oidOf = pure $ LibPQ.Oid 700+instance OidOfArray db 'PGfloat4 where oidOfArray = pure $ LibPQ.Oid 1021+instance OidOf db 'PGfloat8 where oidOf = pure $ LibPQ.Oid 701+instance OidOfArray db 'PGfloat8 where oidOfArray = pure $ LibPQ.Oid 1022+instance OidOf db 'PGmoney where oidOf = pure $ LibPQ.Oid 790+instance OidOfArray db 'PGmoney where oidOfArray = pure $ LibPQ.Oid 791+instance OidOf db ('PGchar n) where oidOf = pure $ LibPQ.Oid 18+instance OidOfArray db ('PGchar n) where oidOfArray = pure $ LibPQ.Oid 1002+instance OidOf db ('PGvarchar n) where oidOf = pure $ LibPQ.Oid 1043+instance OidOfArray db ('PGvarchar n) where oidOfArray = pure $ LibPQ.Oid 1015+instance OidOf db 'PGtext where oidOf = pure $ LibPQ.Oid 25+instance OidOfArray db 'PGtext where oidOfArray = pure $ LibPQ.Oid 1009+instance OidOf db 'PGbytea where oidOf = pure $ LibPQ.Oid 17+instance OidOfArray db 'PGbytea where oidOfArray = pure $ LibPQ.Oid 1001+instance OidOf db 'PGtimestamp where oidOf = pure $ LibPQ.Oid 1114+instance OidOfArray db 'PGtimestamp where oidOfArray = pure $ LibPQ.Oid 1115+instance OidOf db 'PGtimestamptz where oidOf = pure $ LibPQ.Oid 1184+instance OidOfArray db 'PGtimestamptz where oidOfArray = pure $ LibPQ.Oid 1185+instance OidOf db 'PGdate where oidOf = pure $ LibPQ.Oid 1082+instance OidOfArray db 'PGdate where oidOfArray = pure $ LibPQ.Oid 1182+instance OidOf db 'PGtime where oidOf = pure $ LibPQ.Oid 1083+instance OidOfArray db 'PGtime where oidOfArray = pure $ LibPQ.Oid 1183+instance OidOf db 'PGtimetz where oidOf = pure $ LibPQ.Oid 1266+instance OidOfArray db 'PGtimetz where oidOfArray = pure $ LibPQ.Oid 1270+instance OidOf db 'PGinterval where oidOf = pure $ LibPQ.Oid 1186+instance OidOfArray db 'PGinterval where oidOfArray = pure $ LibPQ.Oid 1187+instance OidOf db 'PGuuid where oidOf = pure $ LibPQ.Oid 2950+instance OidOfArray db 'PGuuid where oidOfArray = pure $ LibPQ.Oid 2951+instance OidOf db 'PGinet where oidOf = pure $ LibPQ.Oid 869+instance OidOfArray db 'PGinet where oidOfArray = pure $ LibPQ.Oid 1041+instance OidOf db 'PGjson where oidOf = pure $ LibPQ.Oid 114+instance OidOfArray db 'PGjson where oidOfArray = pure $ LibPQ.Oid 199+instance OidOf db 'PGjsonb where oidOf = pure $ LibPQ.Oid 3802+instance OidOfArray db 'PGjsonb where oidOfArray = pure $ LibPQ.Oid 3807+instance OidOf db 'PGtsvector where oidOf = pure $ LibPQ.Oid 3614+instance OidOfArray db 'PGtsvector where oidOfArray = pure $ LibPQ.Oid 3643+instance OidOf db 'PGtsquery where oidOf = pure $ LibPQ.Oid 3615+instance OidOfArray db 'PGtsquery where oidOfArray = pure $ LibPQ.Oid 3645+instance OidOf db 'PGoid where oidOf = pure $ LibPQ.Oid 26+instance OidOfArray db 'PGoid where oidOfArray = pure $ LibPQ.Oid 1028+instance OidOf db ('PGrange 'PGint4) where oidOf = pure $ LibPQ.Oid 3904+instance OidOfArray db ('PGrange 'PGint4) where oidOfArray = pure $ LibPQ.Oid 3905+instance OidOf db ('PGrange 'PGint8) where oidOf = pure $ LibPQ.Oid 3926+instance OidOfArray db ('PGrange 'PGint8) where oidOfArray = pure $ LibPQ.Oid 3927+instance OidOf db ('PGrange 'PGnumeric) where oidOf = pure $ LibPQ.Oid 3906+instance OidOfArray db ('PGrange 'PGnumeric) where oidOfArray = pure $ LibPQ.Oid 3907+instance OidOf db ('PGrange 'PGtimestamp) where oidOf = pure $ LibPQ.Oid 3908+instance OidOfArray db ('PGrange 'PGtimestamp) where oidOfArray = pure $ LibPQ.Oid 3909+instance OidOf db ('PGrange 'PGtimestamptz) where oidOf = pure $ LibPQ.Oid 3910+instance OidOfArray db ('PGrange 'PGtimestamptz) where oidOfArray = pure $ LibPQ.Oid 3911+instance OidOf db ('PGrange 'PGdate) where oidOf = pure $ LibPQ.Oid 3912+instance OidOfArray db ('PGrange 'PGdate) where oidOfArray = pure $ LibPQ.Oid 3913+instance+ ( UserType db ('PGcomposite row) ~ '(sch,td)+ , Has sch db schema+ , Has td schema ('Typedef ('PGcomposite row)) )+ => OidOf db ('PGcomposite row) where+ oidOf = oidOfTypedef (QualifiedAlias @sch @td)+instance+ ( UserType db ('PGcomposite row) ~ '(sch,td)+ , Has sch db schema+ , Has td schema ('Typedef ('PGcomposite row)) )+ => OidOfArray db ('PGcomposite row) where+ oidOfArray = oidOfArrayTypedef (QualifiedAlias @sch @td)+instance+ ( UserType db ('PGenum labels) ~ '(sch,td)+ , Has sch db schema+ , Has td schema ('Typedef ('PGenum labels)) )+ => OidOf db ('PGenum labels) where+ oidOf = oidOfTypedef (QualifiedAlias @sch @td)+instance+ ( UserType db ('PGenum labels) ~ '(sch,td)+ , Has sch db schema+ , Has td schema ('Typedef ('PGenum labels)) )+ => OidOfArray db ('PGenum labels) where+ oidOfArray = oidOfArrayTypedef (QualifiedAlias @sch @td)++oidOfTypedef+ :: (Has sch db schema, Has ty schema pg)+ => QualifiedAlias sch ty+ -> ReaderT (SOP.K LibPQ.Connection db) IO LibPQ.Oid+oidOfTypedef (_ :: QualifiedAlias sch ty) = ReaderT $ \(SOP.K conn) -> do+ resultMaybe <- LibPQ.execParams conn q [] LibPQ.Binary+ case resultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.execParams"+ Just result -> do+ valueMaybe <- LibPQ.getvalue result 0 0+ case valueMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.getvalue"+ Just value -> case valueParser int value of+ Left err -> throwIO $ DecodingException "oidOfTypedef" err+ Right oid -> return $ LibPQ.Oid oid+ where+ q = ByteString.intercalate " "+ [ "SELECT pg_type.oid"+ , "FROM pg_type"+ , "INNER JOIN pg_namespace"+ , "ON pg_type.typnamespace = pg_namespace.oid"+ , "WHERE pg_type.typname = "+ , "\'" <> fromString (symbolVal (SOP.Proxy @ty)) <> "\'"+ , "AND pg_namespace.nspname = "+ , "\'" <> fromString (symbolVal (SOP.Proxy @sch)) <> "\'"+ , ";" ]++oidOfArrayTypedef+ :: (Has sch db schema, Has ty schema pg)+ => QualifiedAlias sch ty+ -> ReaderT (SOP.K LibPQ.Connection db) IO LibPQ.Oid+oidOfArrayTypedef (_ :: QualifiedAlias sch ty) = ReaderT $ \(SOP.K conn) -> do+ resultMaybe <- LibPQ.execParams conn q [] LibPQ.Binary+ case resultMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.execParams"+ Just result -> do+ valueMaybe <- LibPQ.getvalue result 0 0+ case valueMaybe of+ Nothing -> throwIO $ ConnectionException "LibPQ.getvalue"+ Just value -> case valueParser int value of+ Left err -> throwIO $ DecodingException "oidOfArray" err+ Right oid -> return $ LibPQ.Oid oid+ where+ q = ByteString.intercalate " "+ [ "SELECT pg_type.typelem"+ , "FROM pg_type"+ , "INNER JOIN pg_namespace"+ , "ON pg_type.typnamespace = pg_namespace.oid"+ , "WHERE pg_type.typname = "+ , "\'" <> fromString (symbolVal (SOP.Proxy @ty)) <> "\'"+ , "AND pg_namespace.nspname = "+ , "\'" <> fromString (symbolVal (SOP.Proxy @sch)) <> "\'"+ , ";" ]
+ src/Squeal/PostgreSQL/Session/Pool.hs view
@@ -0,0 +1,124 @@+{-|+Module: Squeal.PostgreSQL.Pool+Description: connection pools+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Connection pools.++Typical use case would be to create your pool using `createConnectionPool`+and run anything that requires the pool connection with `usingConnectionPool`.++Here's a simplified example:++>>> import Squeal.PostgreSQL++>>> :{+do+ let+ query :: Query_ (Public '[]) () (Only Char)+ query = values_ (inline 'a' `as` #fromOnly)+ pool <- createConnectionPool "host=localhost port=5432 dbname=exampledb" 1 0.5 10+ chr <- usingConnectionPool pool $ do+ result <- runQuery query+ Just (Only a) <- firstRow result+ return a+ destroyConnectionPool pool+ putChar chr+:}+a+-}++{-# LANGUAGE+ DeriveFunctor+ , FlexibleContexts+ , FlexibleInstances+ , InstanceSigs+ , MultiParamTypeClasses+ , PolyKinds+ , RankNTypes+ , ScopedTypeVariables+ , TypeFamilies+ , TypeInType+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Session.Pool+ ( -- * Pool+ Pool+ , createConnectionPool+ , usingConnectionPool+ , destroyConnectionPool+ ) where++import Data.ByteString+import Data.Time+import UnliftIO (MonadUnliftIO (..))+import UnliftIO.Pool (Pool, createPool, destroyAllResources, withResource)++import Squeal.PostgreSQL.Type.Schema+import Squeal.PostgreSQL.Session (PQ (..))+import Squeal.PostgreSQL.Session.Connection++-- | Create a striped pool of connections.+-- Although the garbage collector will destroy all idle connections when the pool is garbage collected it's recommended to manually `destroyAllResources` when you're done with the pool so that the connections are freed up as soon as possible.+createConnectionPool+ :: forall (db :: SchemasType) io. MonadUnliftIO io+ => ByteString+ -- ^ The passed string can be empty to use all default parameters, or it can+ -- contain one or more parameter settings separated by whitespace.+ -- Each parameter setting is in the form keyword = value. Spaces around the equal+ -- sign are optional. To write an empty value or a value containing spaces,+ -- surround it with single quotes, e.g., keyword = 'a value'. Single quotes and+ -- backslashes within the value must be escaped with a backslash, i.e., ' and \.+ -> Int+ -- ^ The number of stripes (distinct sub-pools) to maintain. The smallest acceptable value is 1.+ -> NominalDiffTime+ -- ^ Amount of time for which an unused connection is kept open. The smallest acceptable value is 0.5 seconds.+ -- The elapsed time before destroying a connection may be a little longer than requested, as the reaper thread wakes at 1-second intervals.+ -> Int+ -- ^ Maximum number of connections to keep open per stripe. The smallest acceptable value is 1.+ -- Requests for connections will block if this limit is reached on a single stripe, even if other stripes have idle connections available.+ -> io (Pool (K Connection db))+createConnectionPool conninfo stripes idle maxResrc =+ createPool (connectdb conninfo) finish stripes idle maxResrc++{-|+Temporarily take a connection from a `Pool`, perform an action with it,+and return it to the pool afterwards.++If the pool has an idle connection available, it is used immediately.+Otherwise, if the maximum number of connections has not yet been reached,+a new connection is created and used.+If the maximum number of connections has been reached, this function blocks+until a connection becomes available.+-}+usingConnectionPool+ :: MonadUnliftIO io+ => Pool (K Connection db) -- ^ pool+ -> PQ db db io x -- ^ session+ -> io x+usingConnectionPool pool (PQ session) = unK <$> withResource pool session++{- |+Destroy all connections in all stripes in the pool.+Note that this will ignore any exceptions in the destroy function.++This function is useful when you detect that all connections+in the pool are broken. For example after a database has been+restarted all connections opened before the restart will be broken.+In that case it's better to close those connections so that+`usingConnectionPool` won't take a broken connection from the pool+but will open a new connection instead.++Another use-case for this function is that when you know you are done+with the pool you can destroy all idle connections immediately+instead of waiting on the garbage collector to destroy them,+thus freeing up those connections sooner.+-}+destroyConnectionPool+ :: MonadUnliftIO io+ => Pool (K Connection db) -- ^ pool+ -> io ()+destroyConnectionPool = destroyAllResources
+ src/Squeal/PostgreSQL/Session/Result.hs view
@@ -0,0 +1,182 @@+{-|+Module: Squeal.PostgreSQL.Session.Result+Description: results+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Get values from a `Result`.+-}++{-# LANGUAGE+ FlexibleContexts+ , GADTs+ , OverloadedStrings+ , ScopedTypeVariables+ , TypeApplications+#-}++module Squeal.PostgreSQL.Session.Result+ ( Result (..)+ , getRow+ , firstRow+ , getRows+ , nextRow+ , ntuples+ , nfields+ , resultStatus+ , okResult+ , resultErrorMessage+ , resultErrorCode+ ) where++import Control.Exception (throw)+import Control.Monad (when)+import Control.Monad.IO.Class+import Data.ByteString (ByteString)+import Data.Text (Text)+import Data.Traversable (for)++import qualified Database.PostgreSQL.LibPQ as LibPQ+import qualified Generics.SOP as SOP++import Squeal.PostgreSQL.Session.Decode+import Squeal.PostgreSQL.Session.Exception++{- | `Result`s are generated by running+`Squeal.PostgreSQL.Session.Statement`s+in a `Squeal.PostgreSQL.Session.Monad.MonadPQ`.++They contain an underlying `LibPQ.Result`+and a `DecodeRow`.+-}+data Result y where+ Result+ :: SOP.SListI row+ => DecodeRow row y+ -> LibPQ.Result+ -> Result y+instance Functor Result where+ fmap f (Result decode result) = Result (fmap f decode) result++-- | Get a row corresponding to a given row number from a `LibPQ.Result`,+-- throwing an exception if the row number is out of bounds.+getRow :: MonadIO io => LibPQ.Row -> Result y -> io y+getRow r (Result decode result) = liftIO $ do+ numRows <- LibPQ.ntuples result+ numCols <- LibPQ.nfields result+ when (numRows < r) $ throw $ RowsException "getRow" r numRows+ row' <- traverse (LibPQ.getvalue result r) [0 .. numCols - 1]+ case SOP.fromList row' of+ Nothing -> throw $ ColumnsException "getRow" numCols+ Just row -> case execDecodeRow decode row of+ Left parseError -> throw $ DecodingException "getRow" parseError+ Right y -> return y++-- | Intended to be used for unfolding in streaming libraries, `nextRow`+-- takes a total number of rows (which can be found with `ntuples`)+-- and a `LibPQ.Result` and given a row number if it's too large returns `Nothing`,+-- otherwise returning the row along with the next row number.+nextRow+ :: MonadIO io+ => LibPQ.Row -- ^ total number of rows+ -> Result y -- ^ result+ -> LibPQ.Row -- ^ row number+ -> io (Maybe (LibPQ.Row, y))+nextRow total (Result decode result) r+ = liftIO $ if r >= total then return Nothing else do+ numCols <- LibPQ.nfields result+ row' <- traverse (LibPQ.getvalue result r) [0 .. numCols - 1]+ case SOP.fromList row' of+ Nothing -> throw $ ColumnsException "nextRow" numCols+ Just row -> case execDecodeRow decode row of+ Left parseError -> throw $ DecodingException "nextRow" parseError+ Right y -> return $ Just (r+1, y)++-- | Get all rows from a `LibPQ.Result`.+getRows :: MonadIO io => Result y -> io [y]+getRows (Result decode result) = liftIO $ do+ numCols <- LibPQ.nfields result+ numRows <- LibPQ.ntuples result+ for [0 .. numRows - 1] $ \ r -> do+ row' <- traverse (LibPQ.getvalue result r) [0 .. numCols - 1]+ case SOP.fromList row' of+ Nothing -> throw $ ColumnsException "getRows" numCols+ Just row -> case execDecodeRow decode row of+ Left parseError -> throw $ DecodingException "getRows" parseError+ Right y -> return y++-- | Get the first row if possible from a `LibPQ.Result`.+firstRow :: MonadIO io => Result y -> io (Maybe y)+firstRow (Result decode result) = liftIO $ do+ numRows <- LibPQ.ntuples result+ numCols <- LibPQ.nfields result+ if numRows <= 0 then return Nothing else do+ row' <- traverse (LibPQ.getvalue result 0) [0 .. numCols - 1]+ case SOP.fromList row' of+ Nothing -> throw $ ColumnsException "firstRow" numCols+ Just row -> case execDecodeRow decode row of+ Left parseError -> throw $ DecodingException "firstRow" parseError+ Right y -> return $ Just y++-- | Lifts actions on results from @LibPQ@.+liftResult+ :: MonadIO io+ => (LibPQ.Result -> IO x)+ -> Result y -> io x+liftResult f (Result _ result) = liftIO $ f result++-- | Returns the number of rows (tuples) in the query result.+ntuples :: MonadIO io => Result y -> io LibPQ.Row+ntuples = liftResult LibPQ.ntuples++-- | Returns the number of columns (fields) in the query result.+nfields :: MonadIO io => Result y -> io LibPQ.Column+nfields = liftResult LibPQ.nfields++-- | Returns the result status of the command.+resultStatus :: MonadIO io => Result y -> io LibPQ.ExecStatus+resultStatus = liftResult LibPQ.resultStatus++okResult_ :: MonadIO io => LibPQ.Result -> io ()+okResult_ result = liftIO $ do+ status <- LibPQ.resultStatus result+ case status of+ LibPQ.CommandOk -> return ()+ LibPQ.TuplesOk -> return ()+ _ -> do+ stateCodeMaybe <- LibPQ.resultErrorField result LibPQ.DiagSqlstate+ case stateCodeMaybe of+ Nothing -> throw $ ConnectionException "LibPQ.resultErrorField"+ Just stateCode -> do+ msgMaybe <- LibPQ.resultErrorMessage result+ case msgMaybe of+ Nothing -> throw $ ConnectionException "LibPQ.resultErrorMessage"+ Just msg -> throw . SQLException $ SQLState status stateCode msg++-- | Check if a `LibPQ.Result`'s status is either `LibPQ.CommandOk`+-- or `LibPQ.TuplesOk` otherwise `throw` a `SQLException`.+okResult :: MonadIO io => SOP.K LibPQ.Result row -> io ()+okResult = okResult_ . SOP.unK++-- | Returns the error message most recently generated by an operation+-- on the connection.+resultErrorMessage+ :: MonadIO io => Result y -> io (Maybe ByteString)+resultErrorMessage = liftResult LibPQ.resultErrorMessage++-- | Returns the error code most recently generated by an operation+-- on the connection.+--+-- https://www.postgresql.org/docs/current/static/errcodes-appendix.html+resultErrorCode+ :: MonadIO io+ => Result y+ -> io (Maybe ByteString)+resultErrorCode = liftResult (flip LibPQ.resultErrorField LibPQ.DiagSqlstate)++execDecodeRow+ :: DecodeRow row y+ -> SOP.NP (SOP.K (Maybe ByteString)) row+ -> Either Text y+execDecodeRow decode = runDecodeRow decode
+ src/Squeal/PostgreSQL/Session/Statement.hs view
@@ -0,0 +1,127 @@+{-|+Module: Squeal.PostgreSQL.Session.Statement+Description: statements+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++A top-level `Statement` type wraps a `Squeal.PostgreSQL.Query.Query`+or `Squeal.PostgreSQL.Manipulation.Manipulation`+together with an `EncodeParams` and a `DecodeRow`.+-}++{-# LANGUAGE+ ConstraintKinds+ , DataKinds+ , DeriveFunctor+ , DeriveFoldable+ , DeriveGeneric+ , DeriveTraversable+ , FlexibleContexts+ , GADTs+ , RankNTypes+#-}++module Squeal.PostgreSQL.Session.Statement+ ( Statement (..)+ , query+ , manipulation+ , GenericParams+ , GenericRow+ ) where++import Data.Functor.Contravariant+import Data.Profunctor (Profunctor (..))++import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP++import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Session.Decode+import Squeal.PostgreSQL.Session.Encode+import Squeal.PostgreSQL.Session.Oid+import Squeal.PostgreSQL.Query+import Squeal.PostgreSQL.Render++-- | A `Statement` consists of a `Squeal.PostgreSQL.Statement.Manipulation`+-- or a `Squeal.PostgreSQL.Session.Statement.Query` that can be run+-- in a `Squeal.PostgreSQL.Session.Monad.MonadPQ`.+data Statement db x y where+ -- | Constructor for a data manipulation language statement+ Manipulation+ :: (SOP.All (OidOfNull db) params, SOP.SListI row)+ => EncodeParams db params x -- ^ encoding of parameters+ -> DecodeRow row y -- ^ decoding of returned rows+ -> Manipulation '[] db params row+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom`, ...+ -> Statement db x y+ -- | Constructor for a structured query language statement+ Query+ :: (SOP.All (OidOfNull db) params, SOP.SListI row)+ => EncodeParams db params x -- ^ encoding of parameters+ -> DecodeRow row y -- ^ decoding of returned rows+ -> Query '[] '[] db params row+ -- ^ `Squeal.PostgreSQL.Query.Select.select`,+ -- `Squeal.PostgreSQL.Query.Values.values`, ...+ -> Statement db x y++instance Profunctor (Statement db) where+ lmap f (Manipulation encode decode q) =+ Manipulation (contramap f encode) decode q+ lmap f (Query encode decode q) =+ Query (contramap f encode) decode q+ rmap f (Manipulation encode decode q) =+ Manipulation encode (fmap f decode) q+ rmap f (Query encode decode q) =+ Query encode (fmap f decode) q+ dimap f g (Manipulation encode decode q) =+ Manipulation (contramap f encode) (fmap g decode) q+ dimap f g (Query encode decode q) =+ Query (contramap f encode) (fmap g decode) q++instance Functor (Statement db x) where fmap = rmap++instance RenderSQL (Statement db x y) where+ renderSQL (Manipulation _ _ q) = renderSQL q+ renderSQL (Query _ _ q) = renderSQL q++-- | A `GenericParams` constraint to ensure that+-- a Haskell type is a product type,+-- all its terms have known Oids,+-- and can be encoded to corresponding+-- Postgres types.+type GenericParams db params x xs =+ ( SOP.All (OidOfNull db) params+ , SOP.IsProductType x xs+ , SOP.AllZip (ToParam db) params xs )++-- | A `GenericRow` constraint to ensure that+-- a Haskell type is a record type,+-- and all its fields and can be decoded from corresponding+-- Postgres fields.+type GenericRow row y ys =+ ( SOP.IsRecord y ys+ , SOP.AllZip FromField row ys )++-- | Smart constructor for a structured query language statement+query ::+ ( GenericParams db params x xs+ , GenericRow row y ys+ ) => Query '[] '[] db params row+ -- ^ `Squeal.PostgreSQL.Query.Select.select`,+ -- `Squeal.PostgreSQL.Query.Values.values`, ...+ -> Statement db x y+query = Query genericParams genericRow++-- | Smart constructor for a data manipulation language statement+manipulation ::+ ( GenericParams db params x xs+ , GenericRow row y ys+ ) => Manipulation '[] db params row+ -- ^ `Squeal.PostgreSQL.Manipulation.Insert.insertInto`,+ -- `Squeal.PostgreSQL.Manipulation.Update.update`,+ -- or `Squeal.PostgreSQL.Manipulation.Delete.deleteFrom`, ...+ -> Statement db x y+manipulation = Manipulation genericParams genericRow
+ src/Squeal/PostgreSQL/Session/Transaction.hs view
@@ -0,0 +1,253 @@+{-|+Module: Squeal.PostgreSQL.Session.Transaction+Description: transaction control language+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++transaction control language+-}++{-# LANGUAGE+ DataKinds+ , FlexibleContexts+ , LambdaCase+ , OverloadedStrings+ , TypeInType+#-}++module Squeal.PostgreSQL.Session.Transaction+ ( -- * Transaction+ transactionally+ , transactionally_+ , transactionallyRetry+ , ephemerally+ , ephemerally_+ , begin+ , commit+ , rollback+ -- * Transaction Mode+ , TransactionMode (..)+ , defaultMode+ , longRunningMode+ , IsolationLevel (..)+ , AccessMode (..)+ , DeferrableMode (..)+ ) where++import UnliftIO++import Squeal.PostgreSQL.Manipulation+import Squeal.PostgreSQL.Render+import Squeal.PostgreSQL.Session.Exception+import Squeal.PostgreSQL.Session.Monad++{- | Run a computation `transactionally`;+first `begin`,+then run the computation,+`onException` `rollback` and rethrow the exception,+otherwise `commit` and `return` the result.+-}+transactionally+ :: (MonadUnliftIO tx, MonadPQ db tx)+ => TransactionMode+ -> tx x -- ^ run inside a transaction+ -> tx x+transactionally mode tx = mask $ \restore -> do+ manipulate_ $ begin mode+ result <- restore tx `onException` (manipulate_ rollback)+ manipulate_ commit+ return result++-- | Run a computation `transactionally_`, in `defaultMode`.+transactionally_+ :: (MonadUnliftIO tx, MonadPQ db tx)+ => tx x -- ^ run inside a transaction+ -> tx x+transactionally_ = transactionally defaultMode++{- |+`transactionallyRetry` a computation;++* first `begin`,+* then `try` the computation,+ - if it raises a serialization failure then `rollback` and restart the transaction,+ - if it raises any other exception then `rollback` and rethrow the exception,+ - otherwise `commit` and `return` the result.+-}+transactionallyRetry+ :: (MonadUnliftIO tx, MonadPQ db tx)+ => TransactionMode+ -> tx x -- ^ run inside a transaction+ -> tx x+transactionallyRetry mode tx = mask $ \restore ->+ loop . try $ do+ x <- restore tx+ manipulate_ commit+ return x+ where+ loop attempt = do+ manipulate_ $ begin mode+ attempt >>= \case+ Left (SerializationFailure _) -> do+ manipulate_ rollback+ loop attempt+ Left err -> do+ manipulate_ rollback+ throwIO err+ Right x -> return x++{- | Run a computation `ephemerally`;+Like `transactionally` but always `rollback`, useful in testing.+-}+ephemerally+ :: (MonadUnliftIO tx, MonadPQ db tx)+ => TransactionMode+ -> tx x -- ^ run inside an ephemeral transaction+ -> tx x+ephemerally mode tx = mask $ \restore -> do+ manipulate_ $ begin mode+ result <- restore tx `onException` (manipulate_ rollback)+ manipulate_ rollback+ return result++{- | Run a computation `ephemerally` in `defaultMode`. -}+ephemerally_+ :: (MonadUnliftIO tx, MonadPQ db tx)+ => tx x -- ^ run inside an ephemeral transaction+ -> tx x+ephemerally_ = ephemerally defaultMode++-- | @BEGIN@ a transaction.+begin :: TransactionMode -> Manipulation_ db () ()+begin mode = UnsafeManipulation $ "BEGIN" <+> renderSQL mode++-- | @COMMIT@ a transaction.+commit :: Manipulation_ db () ()+commit = UnsafeManipulation "COMMIT"++-- | @ROLLBACK@ a transaction.+rollback :: Manipulation_ db () ()+rollback = UnsafeManipulation "ROLLBACK"++-- | The available transaction characteristics are the transaction `IsolationLevel`,+-- the transaction `AccessMode` (`ReadWrite` or `ReadOnly`), and the `DeferrableMode`.+data TransactionMode = TransactionMode+ { isolationLevel :: IsolationLevel+ , accessMode :: AccessMode+ , deferrableMode :: DeferrableMode+ } deriving (Show, Eq)++-- | `TransactionMode` with a `Serializable` `IsolationLevel`,+-- `ReadWrite` `AccessMode` and `NotDeferrable` `DeferrableMode`.+defaultMode :: TransactionMode+defaultMode = TransactionMode ReadCommitted ReadWrite NotDeferrable++-- | `TransactionMode` with a `Serializable` `IsolationLevel`,+-- `ReadOnly` `AccessMode` and `Deferrable` `DeferrableMode`.+-- This mode is well suited for long-running reports or backups.+longRunningMode :: TransactionMode+longRunningMode = TransactionMode Serializable ReadOnly Deferrable++-- | Render a `TransactionMode`.+instance RenderSQL TransactionMode where+ renderSQL mode =+ "ISOLATION LEVEL"+ <+> renderSQL (isolationLevel mode)+ <+> renderSQL (accessMode mode)+ <+> renderSQL (deferrableMode mode)++-- | The SQL standard defines four levels of transaction isolation.+-- The most strict is `Serializable`, which is defined by the standard in a paragraph+-- which says that any concurrent execution of a set of `Serializable` transactions is+-- guaranteed to produce the same effect as running them one at a time in some order.+-- The other three levels are defined in terms of phenomena, resulting from interaction+-- between concurrent transactions, which must not occur at each level.+-- The phenomena which are prohibited at various levels are:+--+-- __Dirty read__: A transaction reads data written by a concurrent uncommitted transaction.+--+-- __Nonrepeatable read__: A transaction re-reads data it has previously read and finds that data+-- has been modified by another transaction (that committed since the initial read).+--+-- __Phantom read__: A transaction re-executes a query returning a set of rows that satisfy+-- a search condition and finds that the set of rows satisfying the condition+-- has changed due to another recently-committed transaction.+--+-- __Serialization anomaly__: The result of successfully committing a group of transactions is inconsistent+-- with all possible orderings of running those transactions one at a time.+--+-- In PostgreSQL, you can request any of the four standard transaction+-- isolation levels, but internally only three distinct isolation levels are implemented,+-- i.e. PostgreSQL's `ReadUncommitted` mode behaves like `ReadCommitted`.+-- This is because it is the only sensible way to map the standard isolation levels to+-- PostgreSQL's multiversion concurrency control architecture.+data IsolationLevel+ = Serializable+ -- ^ Dirty read is not possible.+ -- Nonrepeatable read is not possible.+ -- Phantom read is not possible.+ -- Serialization anomaly is not possible.+ | RepeatableRead+ -- ^ Dirty read is not possible.+ -- Nonrepeatable read is not possible.+ -- Phantom read is not possible.+ -- Serialization anomaly is possible.+ | ReadCommitted+ -- ^ Dirty read is not possible.+ -- Nonrepeatable read is possible.+ -- Phantom read is possible.+ -- Serialization anomaly is possible.+ | ReadUncommitted+ -- ^ Dirty read is not possible.+ -- Nonrepeatable read is possible.+ -- Phantom read is possible.+ -- Serialization anomaly is possible.+ deriving (Show, Eq)++-- | Render an `IsolationLevel`.+instance RenderSQL IsolationLevel where+ renderSQL = \case+ Serializable -> "SERIALIZABLE"+ ReadCommitted -> "READ COMMITTED"+ ReadUncommitted -> "READ UNCOMMITTED"+ RepeatableRead -> "REPEATABLE READ"++-- | The transaction access mode determines whether the transaction is `ReadWrite` or `ReadOnly`.+-- `ReadWrite` is the default. When a transaction is `ReadOnly`,+-- the following SQL commands are disallowed:+-- @INSERT@, @UPDATE@, @DELETE@, and @COPY FROM@+-- if the table they would write to is not a temporary table;+-- all @CREATE@, @ALTER@, and @DROP@ commands;+-- @COMMENT@, @GRANT@, @REVOKE@, @TRUNCATE@;+-- and @EXPLAIN ANALYZE@ and @EXECUTE@ if the command they would execute is among those listed.+-- This is a high-level notion of `ReadOnly` that does not prevent all writes to disk.+data AccessMode+ = ReadWrite+ | ReadOnly+ deriving (Show, Eq)++-- | Render an `AccessMode`.+instance RenderSQL AccessMode where+ renderSQL = \case+ ReadWrite -> "READ WRITE"+ ReadOnly -> "READ ONLY"++-- | The `Deferrable` transaction property has no effect+-- unless the transaction is also `Serializable` and `ReadOnly`.+-- When all three of these properties are selected for a transaction,+-- the transaction may block when first acquiring its snapshot,+-- after which it is able to run without the normal overhead of a+-- `Serializable` transaction and without any risk of contributing+-- to or being canceled by a serialization failure.+-- This `longRunningMode` is well suited for long-running reports or backups.+data DeferrableMode+ = Deferrable+ | NotDeferrable+ deriving (Show, Eq)++-- | Render a `DeferrableMode`.+instance RenderSQL DeferrableMode where+ renderSQL = \case+ Deferrable -> "DEFERRABLE"+ NotDeferrable -> "NOT DEFERRABLE"
− src/Squeal/PostgreSQL/Transaction.hs
@@ -1,252 +0,0 @@-{-|-Module: Squeal.PostgreSQL.Transaction-Description: Squeal transaction control language-Copyright: (c) Eitan Chatav, 2019-Maintainer: eitan@morphism.tech-Stability: experimental--Squeal transaction control language.--}--{-# LANGUAGE- DataKinds- , FlexibleContexts- , LambdaCase- , OverloadedStrings- , TypeInType-#-}--module Squeal.PostgreSQL.Transaction- ( -- * Transaction- transactionally- , transactionally_- , transactionallyRetry- , ephemerally- , ephemerally_- , begin- , commit- , rollback- -- * Transaction Mode- , TransactionMode (..)- , defaultMode- , longRunningMode- , IsolationLevel (..)- , AccessMode (..)- , DeferrableMode (..)- ) where--import UnliftIO--import Squeal.PostgreSQL.Manipulation-import Squeal.PostgreSQL.Render-import Squeal.PostgreSQL.PQ--{- | Run a computation `transactionally`;-first `begin`,-then run the computation,-`onException` `rollback` and rethrow the exception,-otherwise `commit` and `return` the result.--}-transactionally- :: (MonadUnliftIO tx, MonadPQ schemas tx)- => TransactionMode- -> tx x -- ^ run inside a transaction- -> tx x-transactionally mode tx = mask $ \restore -> do- manipulate_ $ begin mode- result <- restore tx `onException` (manipulate_ rollback)- manipulate_ commit- return result---- | Run a computation `transactionally_`, in `defaultMode`.-transactionally_- :: (MonadUnliftIO tx, MonadPQ schemas tx)- => tx x -- ^ run inside a transaction- -> tx x-transactionally_ = transactionally defaultMode--{- |-`transactionallyRetry` a computation;--* first `begin`,-* then `try` the computation,- - if it raises a serialization failure then `rollback` and restart the transaction,- - if it raises any other exception then `rollback` and rethrow the exception,- - otherwise `commit` and `return` the result.--}-transactionallyRetry- :: (MonadUnliftIO tx, MonadPQ schemas tx)- => TransactionMode- -> tx x -- ^ run inside a transaction- -> tx x-transactionallyRetry mode tx = mask $ \restore ->- loop . try $ do- x <- restore tx- manipulate_ commit- return x- where- loop attempt = do- manipulate_ $ begin mode- attempt >>= \case- Left (PQException (PQState _ (Just "40001") _)) -> do- manipulate_ rollback- loop attempt- Left err -> do- manipulate_ rollback- throwIO err- Right x -> return x--{- | Run a computation `ephemerally`;-Like `transactionally` but always `rollback`, useful in testing.--}-ephemerally- :: (MonadUnliftIO tx, MonadPQ schemas tx)- => TransactionMode- -> tx x -- ^ run inside an ephemeral transaction- -> tx x-ephemerally mode tx = mask $ \restore -> do- manipulate_ $ begin mode- result <- restore tx `onException` (manipulate_ rollback)- manipulate_ rollback- return result--{- | Run a computation `ephemerally` in `defaultMode`. -}-ephemerally_- :: (MonadUnliftIO tx, MonadPQ schemas tx)- => tx x -- ^ run inside an ephemeral transaction- -> tx x-ephemerally_ = ephemerally defaultMode---- | @BEGIN@ a transaction.-begin :: TransactionMode -> Manipulation_ schemas () ()-begin mode = UnsafeManipulation $ "BEGIN" <+> renderSQL mode---- | @COMMIT@ a transaction.-commit :: Manipulation_ schemas () ()-commit = UnsafeManipulation "COMMIT"---- | @ROLLBACK@ a transaction.-rollback :: Manipulation_ schemas () ()-rollback = UnsafeManipulation "ROLLBACK"---- | The available transaction characteristics are the transaction `IsolationLevel`,--- the transaction `AccessMode` (`ReadWrite` or `ReadOnly`), and the `DeferrableMode`.-data TransactionMode = TransactionMode- { isolationLevel :: IsolationLevel- , accessMode :: AccessMode- , deferrableMode :: DeferrableMode- } deriving (Show, Eq)---- | `TransactionMode` with a `Serializable` `IsolationLevel`,--- `ReadWrite` `AccessMode` and `NotDeferrable` `DeferrableMode`.-defaultMode :: TransactionMode-defaultMode = TransactionMode ReadCommitted ReadWrite NotDeferrable---- | `TransactionMode` with a `Serializable` `IsolationLevel`,--- `ReadOnly` `AccessMode` and `Deferrable` `DeferrableMode`.--- This mode is well suited for long-running reports or backups.-longRunningMode :: TransactionMode-longRunningMode = TransactionMode Serializable ReadOnly Deferrable---- | Render a `TransactionMode`.-instance RenderSQL TransactionMode where- renderSQL mode =- "ISOLATION LEVEL"- <+> renderSQL (isolationLevel mode)- <+> renderSQL (accessMode mode)- <+> renderSQL (deferrableMode mode)---- | The SQL standard defines four levels of transaction isolation.--- The most strict is `Serializable`, which is defined by the standard in a paragraph--- which says that any concurrent execution of a set of `Serializable` transactions is--- guaranteed to produce the same effect as running them one at a time in some order.--- The other three levels are defined in terms of phenomena, resulting from interaction--- between concurrent transactions, which must not occur at each level.--- The phenomena which are prohibited at various levels are:------ __Dirty read__: A transaction reads data written by a concurrent uncommitted transaction.------ __Nonrepeatable read__: A transaction re-reads data it has previously read and finds that data--- has been modified by another transaction (that committed since the initial read).------ __Phantom read__: A transaction re-executes a query returning a set of rows that satisfy--- a search condition and finds that the set of rows satisfying the condition--- has changed due to another recently-committed transaction.------ __Serialization anomaly__: The result of successfully committing a group of transactions is inconsistent--- with all possible orderings of running those transactions one at a time.------ In PostgreSQL, you can request any of the four standard transaction--- isolation levels, but internally only three distinct isolation levels are implemented,--- i.e. PostgreSQL's `ReadUncommitted` mode behaves like `ReadCommitted`.--- This is because it is the only sensible way to map the standard isolation levels to--- PostgreSQL's multiversion concurrency control architecture.-data IsolationLevel- = Serializable- -- ^ Dirty read is not possible.- -- Nonrepeatable read is not possible.- -- Phantom read is not possible.- -- Serialization anomaly is not possible.- | RepeatableRead- -- ^ Dirty read is not possible.- -- Nonrepeatable read is not possible.- -- Phantom read is not possible.- -- Serialization anomaly is possible.- | ReadCommitted- -- ^ Dirty read is not possible.- -- Nonrepeatable read is possible.- -- Phantom read is possible.- -- Serialization anomaly is possible.- | ReadUncommitted- -- ^ Dirty read is not possible.- -- Nonrepeatable read is possible.- -- Phantom read is possible.- -- Serialization anomaly is possible.- deriving (Show, Eq)---- | Render an `IsolationLevel`.-instance RenderSQL IsolationLevel where- renderSQL = \case- Serializable -> "SERIALIZABLE"- ReadCommitted -> "READ COMMITTED"- ReadUncommitted -> "READ UNCOMMITTED"- RepeatableRead -> "REPEATABLE READ"---- | The transaction access mode determines whether the transaction is `ReadWrite` or `ReadOnly`.--- `ReadWrite` is the default. When a transaction is `ReadOnly`,--- the following SQL commands are disallowed:--- @INSERT@, @UPDATE@, @DELETE@, and @COPY FROM@--- if the table they would write to is not a temporary table;--- all @CREATE@, @ALTER@, and @DROP@ commands;--- @COMMENT@, @GRANT@, @REVOKE@, @TRUNCATE@;--- and @EXPLAIN ANALYZE@ and @EXECUTE@ if the command they would execute is among those listed.--- This is a high-level notion of `ReadOnly` that does not prevent all writes to disk.-data AccessMode- = ReadWrite- | ReadOnly- deriving (Show, Eq)---- | Render an `AccessMode`.-instance RenderSQL AccessMode where- renderSQL = \case- ReadWrite -> "READ WRITE"- ReadOnly -> "READ ONLY"---- | The `Deferrable` transaction property has no effect--- unless the transaction is also `Serializable` and `ReadOnly`.--- When all three of these properties are selected for a transaction,--- the transaction may block when first acquiring its snapshot,--- after which it is able to run without the normal overhead of a--- `Serializable` transaction and without any risk of contributing--- to or being canceled by a serialization failure.--- This `longRunningMode` is well suited for long-running reports or backups.-data DeferrableMode- = Deferrable- | NotDeferrable- deriving (Show, Eq)---- | Render a `DeferrableMode`.-instance RenderSQL DeferrableMode where- renderSQL = \case- Deferrable -> "DEFERRABLE"- NotDeferrable -> "NOT DEFERRABLE"
+ src/Squeal/PostgreSQL/Type.hs view
@@ -0,0 +1,161 @@+{-|+Module: Squeal.PostgreSQL.Type+Description: types+Copyright: (c) Eitan Chatav, 2010+Maintainer: eitan@morphism.tech+Stability: experimental++types+-}+{-# LANGUAGE+ AllowAmbiguousTypes+ , CPP+ , DeriveAnyClass+ , DeriveFoldable+ , DeriveFunctor+ , DeriveGeneric+ , DeriveTraversable+ , DerivingStrategies+ , DefaultSignatures+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Type+ ( Money (..)+ , Json (..)+ , Jsonb (..)+ , Composite (..)+ , Enumerated (..)+ , VarArray (..)+ , FixArray (..)+ , VarChar, varChar, getVarChar+ , FixChar, fixChar, getFixChar+ , Only (..)+ ) where++import Data.Proxy+import Data.Int (Int64)+import GHC.TypeLits++import qualified Data.Text as Strict (Text)+import qualified Data.Text as Strict.Text+import qualified GHC.Generics as GHC+import qualified Generics.SOP as SOP++-- $setup+-- >>> import Squeal.PostgreSQL++{- | The `Money` newtype stores a monetary value in terms+of the number of cents, i.e. @$2,000.20@ would be expressed as+@Money { cents = 200020 }@.+-}+newtype Money = Money { cents :: Int64 }+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++{- | The `Json` newtype is an indication that the Haskell+type it's applied to should be stored as a+`Squeal.PostgreSQL.Type.Schema.PGjson`.+-}+newtype Json hask = Json {getJson :: hask}+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++{- | The `Jsonb` newtype is an indication that the Haskell+type it's applied to should be stored as a+`Squeal.PostgreSQL.Type.Schema.PGjsonb`.+-}+newtype Jsonb hask = Jsonb {getJsonb :: hask}+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++{- | The `Composite` newtype is an indication that the Haskell+type it's applied to should be stored as a+`Squeal.PostgreSQL.Type.Schema.PGcomposite`.+-}+newtype Composite record = Composite {getComposite :: record}+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++{- | The `Enumerated` newtype is an indication that the Haskell+type it's applied to should be stored as a+`Squeal.PostgreSQL.Type.Schema.PGenum`.+-}+newtype Enumerated enum = Enumerated {getEnumerated :: enum}+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++{- | The `VarArray` newtype is an indication that the Haskell+type it's applied to should be stored as a+`Squeal.PostgreSQL.Type.Schema.PGvararray`.++>>> import Data.Vector+>>> :kind! PG (VarArray (Vector Double))+PG (VarArray (Vector Double)) :: PGType+= 'PGvararray ('NotNull 'PGfloat8)+-}+newtype VarArray arr+ = VarArray {getVarArray :: arr}+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++{- | The `FixArray` newtype is an indication that the Haskell+type it's applied to should be stored as a+`Squeal.PostgreSQL.Type.Schema.PGfixarray`.++>>> :kind! PG (FixArray ((Double, Double), (Double, Double)))+PG (FixArray ((Double, Double), (Double, Double))) :: PGType+= 'PGfixarray '[2, 2] ('NotNull 'PGfloat8)+-}+newtype FixArray arr = FixArray {getFixArray :: arr}+ deriving stock (Eq, Ord, Show, Read, GHC.Generic)+ deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)++-- | `Only` is a 1-tuple type, useful for encoding or decoding a singleton+newtype Only x = Only { fromOnly :: x }+ deriving (Functor,Foldable,Traversable,Eq,Ord,Read,Show,GHC.Generic)+instance SOP.Generic (Only x)+instance SOP.HasDatatypeInfo (Only x)++-- | Variable-length text type with limit+newtype VarChar (n :: Nat) = VarChar Strict.Text+ deriving (Eq,Ord,Read,Show)++-- | Constructor for `VarChar`+varChar :: forall n . KnownNat n => Strict.Text -> Maybe (VarChar n)+varChar t =+ if Strict.Text.length t <= fromIntegral (natVal @n Proxy)+ then Just $ VarChar t+ else Nothing++-- | Access the `Strict.Text` of a `VarChar`+getVarChar :: VarChar n -> Strict.Text+getVarChar (VarChar t) = t++-- | Fixed-length, blank padded+newtype FixChar (n :: Nat) = FixChar Strict.Text+ deriving (Eq,Ord,Read,Show)++-- | Constructor for `FixChar`+fixChar :: forall n . KnownNat n => Strict.Text -> Maybe (FixChar n)+fixChar t =+ if Strict.Text.length t == fromIntegral (natVal @n Proxy)+ then Just $ FixChar t+ else Nothing++-- | Access the `Strict.Text` of a `FixChar`+getFixChar :: FixChar n -> Strict.Text+getFixChar (FixChar t) = t
+ src/Squeal/PostgreSQL/Type/Alias.hs view
@@ -0,0 +1,260 @@+{-|+Module: Squeal.PostgreSQL.Type.Alias+Description: aliases+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++This module embeds Postgres's alias system in Haskell in+a typesafe fashion. Thanks to GHC's @OverloadedLabels@ extension,+Squeal can reference aliases by prepending with a @#@.+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GADTs+ , LambdaCase+ , OverloadedStrings+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilyDependencies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Type.Alias+ ( -- * Aliases+ (:::)+ , Alias (..)+ , IsLabel (..)+ , Aliased (As)+ , Aliasable (as)+ , renderAliased+ , mapAliased+ , Has+ , HasUnique+ , HasAll+ , HasIn+ -- * Qualified Aliases+ , QualifiedAlias (..)+ , IsQualified (..)+ -- * Grouping+ , Grouping (..)+ , GroupedBy+ ) where++import Control.DeepSeq+import Data.ByteString (ByteString)+import Data.String (fromString)+import GHC.OverloadedLabels+import GHC.TypeLits++import qualified Generics.SOP as SOP+import qualified GHC.Generics as GHC++import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render++-- $setup+-- >>> import Squeal.PostgreSQL++-- | The alias operator `:::` is like a promoted version of `As`,+-- a type level pair between an alias and some type.+type (:::) (alias :: Symbol) ty = '(alias,ty)+infixr 6 :::+++-- | `Grouping` is an auxiliary namespace, created by+-- @GROUP BY@ clauses (`Squeal.PostgreSQL.Query.groupBy`), and used+-- for typesafe aggregation+data Grouping+ = Ungrouped -- ^ no aggregation permitted+ | Grouped [(Symbol,Symbol)] -- ^ aggregation required for any column which is not grouped++{- | A `GroupedBy` constraint indicates that a table qualified column is+a member of the auxiliary namespace created by @GROUP BY@ clauses and thus,+may be called in an output `Squeal.PostgreSQL.Expression.Expression` without aggregating.+-}+class (KnownSymbol table, KnownSymbol column)+ => GroupedBy table column bys where+instance {-# OVERLAPPING #-} (KnownSymbol table, KnownSymbol column)+ => GroupedBy table column ('(table,column) ': bys)+instance {-# OVERLAPPABLE #-}+ ( KnownSymbol table+ , KnownSymbol column+ , GroupedBy table column bys+ ) => GroupedBy table column (tabcol ': bys)++-- | `Alias`es are proxies for a type level string or `Symbol`+-- and have an `IsLabel` instance so that with @-XOverloadedLabels@+--+-- >>> :set -XOverloadedLabels+-- >>> #foobar :: Alias "foobar"+-- Alias+data Alias (alias :: Symbol) = Alias+ deriving (Eq,GHC.Generic,Ord,Show,NFData)+instance alias1 ~ alias2 => IsLabel alias1 (Alias alias2) where+ fromLabel = Alias+instance aliases ~ '[alias] => IsLabel alias (NP Alias aliases) where+ fromLabel = fromLabel SOP.:* Nil+-- | >>> printSQL (#jimbob :: Alias "jimbob")+-- "jimbob"+instance KnownSymbol alias => RenderSQL (Alias alias) where+ renderSQL = doubleQuoted . fromString . symbolVal++-- >>> printSQL (#jimbob :* #kandi :: NP Alias '["jimbob", "kandi"])+-- "jimbob", "kandi"+instance SOP.All KnownSymbol aliases => RenderSQL (NP Alias aliases) where+ renderSQL+ = commaSeparated+ . SOP.hcollapse+ . SOP.hcmap (SOP.Proxy @KnownSymbol) (SOP.K . renderSQL)++-- | The `As` operator is used to name an expression. `As` is like a demoted+-- version of `:::`.+--+-- >>> Just "hello" `As` #hi :: Aliased Maybe ("hi" ::: String)+-- As (Just "hello") Alias+data Aliased expression aliased where+ As+ :: KnownSymbol alias+ => expression ty+ -> Alias alias+ -> Aliased expression (alias ::: ty)+deriving instance Show (expression ty)+ => Show (Aliased expression (alias ::: ty))+deriving instance Eq (expression ty)+ => Eq (Aliased expression (alias ::: ty))+deriving instance Ord (expression ty)+ => Ord (Aliased expression (alias ::: ty))+instance (alias0 ~ alias1, alias0 ~ alias2, KnownSymbol alias2)+ => IsLabel alias0 (Aliased Alias (alias1 ::: alias2)) where+ fromLabel = fromLabel @alias2 `As` fromLabel @alias1++-- | The `Aliasable` class provides a way to scrap your `Nil`s+-- in an `NP` list of `Aliased` expressions.+class KnownSymbol alias => Aliasable alias expression aliased+ | aliased -> expression+ , aliased -> alias+ where as :: expression -> Alias alias -> aliased+instance (KnownSymbol alias, aliased ~ (alias ::: ty)) => Aliasable alias+ (expression ty)+ (Aliased expression aliased)+ where+ as = As+instance (KnownSymbol alias, tys ~ '[alias ::: ty]) => Aliasable alias+ (expression ty)+ (NP (Aliased expression) tys)+ where+ expression `as` alias = expression `As` alias SOP.:* Nil++-- | >>> let renderMaybe = fromString . maybe "Nothing" (const "Just")+-- >>> renderAliased renderMaybe (Just (3::Int) `As` #an_int)+-- "Just AS \"an_int\""+renderAliased+ :: (forall ty. expression ty -> ByteString)+ -> Aliased expression aliased+ -> ByteString+renderAliased render (expression `As` alias) =+ render expression <> " AS " <> renderSQL alias++-- | Map a function over an `Aliased` expression.+mapAliased+ :: (expr x -> expr y)+ -> Aliased expr (alias ::: x)+ -> Aliased expr (alias ::: y)+mapAliased f (x `As` alias) = f x `As` alias++-- | @HasUnique alias fields field@ is a constraint that proves that+-- @fields@ is a singleton of @alias ::: field@.+type HasUnique alias fields field = fields ~ '[alias ::: field]++-- | @Has alias fields field@ is a constraint that proves that+-- @fields@ has a field of @alias ::: field@, inferring @field@+-- from @alias@ and @fields@.+class KnownSymbol alias =>+ Has (alias :: Symbol) (fields :: [(Symbol,kind)]) (field :: kind)+ | alias fields -> field where+instance {-# OVERLAPPING #-} (KnownSymbol alias, field0 ~ field1)+ => Has alias (alias ::: field0 ': fields) field1+instance {-# OVERLAPPABLE #-} (KnownSymbol alias, Has alias fields field)+ => Has alias (field' ': fields) field++{-| @HasIn fields (alias ::: field)@ is a constraint that proves that+@fields@ has a field of @alias ::: field@. It is used in @UPDATE@s to+choose which subfields to update.+-}+class HasIn fields field where+instance (Has alias fields field) => HasIn fields (alias ::: field) where++-- | `HasAll` extends `Has` to take lists of @aliases@ and @fields@ and infer+-- a list of @subfields@.+class+ ( SOP.All KnownSymbol aliases+ ) => HasAll+ (aliases :: [Symbol])+ (fields :: [(Symbol,kind)])+ (subfields :: [(Symbol,kind)])+ | aliases fields -> subfields where+instance {-# OVERLAPPING #-} HasAll '[] fields '[]+instance {-# OVERLAPPABLE #-}+ (Has alias fields field, HasAll aliases fields subfields)+ => HasAll (alias ': aliases) fields (alias ::: field ': subfields)++-- | Analagous to `IsLabel`, the constraint+-- `IsQualified` defines `!` for a column alias qualified+-- by a table alias.+class IsQualified qualifier alias expression where+ (!) :: Alias qualifier -> Alias alias -> expression+ infixl 9 !+instance IsQualified qualifier alias (Alias qualifier, Alias alias) where+ (!) = (,)++{-| `QualifiedAlias`es enables multi-schema support by allowing a reference+to a `Squeal.PostgreSQL.Type.Schema.Table`, `Squeal.PostgreSQL.Type.Schema.Typedef`+or `Squeal.PostgreSQL.Type.Schema.View` to be qualified by their schemas. By default,+a qualifier of @public@ is provided.++>>> :{+let+ alias1 :: QualifiedAlias "sch" "tab"+ alias1 = #sch ! #tab+ alias2 :: QualifiedAlias "public" "vw"+ alias2 = #vw+in printSQL alias1 >> printSQL alias2+:}+"sch"."tab"+"vw"+-}+data QualifiedAlias (qualifier :: Symbol) (alias :: Symbol) = QualifiedAlias+ deriving (Eq,GHC.Generic,Ord,Show,NFData)+instance (q ~ q', a ~ a') => IsQualified q a (QualifiedAlias q' a') where+ _ ! _ = QualifiedAlias+instance (q' ~ "public", a ~ a') => IsLabel a (QualifiedAlias q' a') where+ fromLabel = QualifiedAlias+instance (q0 ~ q1, a0 ~ a1, a1 ~ a2, KnownSymbol a2) =>+ IsQualified q0 a0 (Aliased (QualifiedAlias q1) (a1 ::: a2)) where+ _ ! _ = QualifiedAlias `As` Alias+instance (q ~ "public", a0 ~ a1, a1 ~ a2, KnownSymbol a2) =>+ IsLabel a0 (Aliased (QualifiedAlias q) (a1 ::: a2)) where+ fromLabel = QualifiedAlias `As` Alias++instance (KnownSymbol q, KnownSymbol a)+ => RenderSQL (QualifiedAlias q a) where+ renderSQL _ =+ let+ qualifier = renderSQL (Alias @q)+ alias = renderSQL (Alias @a)+ in+ if qualifier == "\"public\"" then alias else qualifier <> "." <> alias
+ src/Squeal/PostgreSQL/Type/List.hs view
@@ -0,0 +1,118 @@+{-|+Module: Squeal.PostgreSQL.Type.List+Description: list related types and functions+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++Haskell singly-linked lists are very powerful. This module+provides functionality for type-level lists, heterogeneous+lists and type aligned lists.+-}++{-# LANGUAGE+ DataKinds+ , FlexibleContexts+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , PolyKinds+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeOperators+ , UndecidableInstances+#-}++module Squeal.PostgreSQL.Type.List+ ( -- * Heterogeneous List+ SOP.NP (..)+ , (*:)+ , one+ , Join+ , disjoin+ , Additional (..)+ -- * Path+ , Path (..)+ -- * Type Level List+ , Elem+ , In+ , Length+ ) where++import Control.Category.Free+import Data.Function ((&))+import Data.Kind+import Data.Type.Bool+import GHC.TypeLits++import Generics.SOP as SOP++-- | `Join` is simply promoted `++` and is used in @JOIN@s in+-- `Squeal.PostgreSQL.Query.FromClause`s.+type family Join xs ys where+ Join '[] ys = ys+ Join (x ': xs) ys = x ': Join xs ys++-- | `disjoin` is a utility function for splitting an `NP` list into pieces.+disjoin+ :: forall xs ys expr. SListI xs+ => NP expr (Join xs ys)+ -> (NP expr xs, NP expr ys)+disjoin = case sList @xs of+ SNil -> \ys -> (Nil, ys)+ SCons -> \(x :* xsys) ->+ case disjoin xsys of (xs,ys) -> (x :* xs, ys)++-- | The `Additional` class is for appending+-- type-level list parameterized constructors such as `NP`,+-- `Squeal.PostgreSQL.Query.Selection`, and `Squeal.PostgreSQL.Query.FromClause`.+class Additional expr where+ also :: expr ys -> expr xs -> expr (Join xs ys)+instance Additional (NP expr) where+ also ys = \case+ Nil -> ys+ x :* xs -> x :* (xs & also ys)++-- | A useful operator for ending an `NP` list of length+-- at least 2 without `Nil`+(*:) :: f x -> f y -> NP f '[x,y]+x *: y = x :* y :* Nil+infixl 8 *:++-- | A list of length `one`.+one :: f x -> NP f '[x]+one f = f :* Nil++-- | @Elem@ is a promoted `Data.List.elem`.+type family Elem x xs where+ Elem x '[] = 'False+ Elem x (x ': _) = 'True+ Elem x (_ ': x ': _) = 'True+ Elem x (_ ': _ ': x ': _) = 'True+ Elem x (_ ': _ ': _ ': x ': _) = 'True+ Elem x (_ ': _ ': _ ': _ ': x ': _) = 'True+ Elem x (_ ': _ ': _ ': _ ': _ ': x ': _) = 'True+ Elem x (_ ': xs) = Elem x xs++-- | @In x xs@ is a constraint that proves that @x@ is in @xs@.+type family In x xs :: Constraint where+ In x xs = If (Elem x xs) (() :: Constraint)+ (TypeError ('ShowType x ':<>: 'Text " is not in " ':<>: 'ShowType xs))++{- | Calculate the `Length` of a type level list++>>> :kind! Length '[Char,String,Bool,Double]+Length '[Char,String,Bool,Double] :: Nat+= 4+-}+type family Length (xs :: [k]) :: Nat where+ Length (_ ': _ ': _ ': _ ': _ : xs) = 5 + Length xs+ Length (_ ': _ ': _ ': _ : xs) = 4 + Length xs+ Length (_ ': _ ': _ : xs) = 3 + Length xs+ Length (_ ': _ : xs) = 2 + Length xs+ Length (_ : xs) = 1 + Length xs+ Length '[] = 0
+ src/Squeal/PostgreSQL/Type/PG.hs view
@@ -0,0 +1,334 @@+{-|+Module: Squeal.PostgreSQL.Type.PG+Description: embedding of Haskell types into Postgres type system+Copyright: (c) Eitan Chatav, 2010+Maintainer: eitan@morphism.tech+Stability: experimental++`Squeal.PostgreSQL.Type.PG` provides type families for turning Haskell+`Type`s into corresponding Postgres types.+-}+{-# LANGUAGE+ AllowAmbiguousTypes+ , CPP+ , DeriveAnyClass+ , DeriveFoldable+ , DeriveFunctor+ , DeriveGeneric+ , DeriveTraversable+ , DerivingStrategies+ , DefaultSignatures+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GADTs+ , LambdaCase+ , MultiParamTypeClasses+ , OverloadedStrings+ , ScopedTypeVariables+ , TypeApplications+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Type.PG+ ( -- * PG+ IsPG (..)+ , NullPG+ , TuplePG+ , RowPG+ -- * Type families+ , LabelsPG+ , DimPG+ , FixPG+ , TupleOf+ , TupleCodeOf+ , RowOf+ , ConstructorsOf+ , ConstructorNameOf+ , ConstructorNamesOf+ ) where++import Data.Aeson (Value)+import Data.Kind (Type)+import Data.Int (Int16, Int32, Int64)+import Data.Scientific (Scientific)+import Data.Time (Day, DiffTime, LocalTime, TimeOfDay, TimeZone, UTCTime)+import Data.Vector (Vector)+import Data.UUID.Types (UUID)+import GHC.TypeLits+import Network.IP.Addr (NetAddr, IP)++import qualified Data.ByteString.Lazy as Lazy (ByteString)+import qualified Data.ByteString as Strict (ByteString)+import qualified Data.Text.Lazy as Lazy (Text)+import qualified Data.Text as Strict (Text)+import qualified Database.PostgreSQL.LibPQ as LibPQ+import qualified Generics.SOP as SOP+import qualified Generics.SOP.Record as SOP+import qualified Generics.SOP.Type.Metadata as Type++import Squeal.PostgreSQL.Type+import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.Schema++-- $setup+-- >>> import Squeal.PostgreSQL+-- >>> import Data.Text (Text)+-- >>> import qualified GHC.Generics as GHC++{- | The `PG` type family embeds a subset of Haskell types+as Postgres types. As an open type family, `PG` is extensible.++>>> :kind! PG LocalTime+PG LocalTime :: PGType+= 'PGtimestamp++The preferred way to generate `PG`s of your own type is through+generalized newtype deriving or via deriving.++>>> newtype UserId = UserId {getUserId :: UUID} deriving newtype IsPG++>>> :kind! PG UserId+PG UserId :: PGType+= 'PGuuid++>>> :{+data Answer = Yes | No+ deriving stock GHC.Generic+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)+ deriving IsPG via Enumerated Answer+:}++>>> :kind! PG Answer+PG Answer :: PGType+= 'PGenum '["Yes", "No"]++>>> :{+data Complex = Complex {real :: Double, imaginary :: Double}+ deriving stock GHC.Generic+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)+ deriving IsPG via Composite Complex+:}++>>> :kind! PG Complex+PG Complex :: PGType+= 'PGcomposite+ '["real" ::: 'NotNull 'PGfloat8,+ "imaginary" ::: 'NotNull 'PGfloat8]+-}+class IsPG (hask :: Type) where type PG hask :: PGType+-- | `PGbool`+instance IsPG Bool where type PG Bool = 'PGbool+-- | `PGint2`+instance IsPG Int16 where type PG Int16 = 'PGint2+-- | `PGint4`+instance IsPG Int32 where type PG Int32 = 'PGint4+-- | `PGint8`+instance IsPG Int64 where type PG Int64 = 'PGint8+-- | `PGint2`+instance IsPG LibPQ.Oid where type PG LibPQ.Oid = 'PGoid+-- | `PGnumeric`+instance IsPG Scientific where type PG Scientific = 'PGnumeric+-- | `PGfloat4`+instance IsPG Float where type PG Float = 'PGfloat4+-- | `PGfloat8`+instance IsPG Double where type PG Double = 'PGfloat8+-- | `PGchar` @1@+instance IsPG Char where type PG Char = 'PGchar 1+-- | `PGtext`+instance IsPG Strict.Text where type PG Strict.Text = 'PGtext+-- | `PGtext`+instance IsPG Lazy.Text where type PG Lazy.Text = 'PGtext+-- | `PGtext`+instance IsPG String where type PG String = 'PGtext+-- | `PGbytea`+instance IsPG Strict.ByteString where type PG Strict.ByteString = 'PGbytea+-- | `PGbytea`+instance IsPG Lazy.ByteString where type PG Lazy.ByteString = 'PGbytea+-- | `PGtimestamp`+instance IsPG LocalTime where type PG LocalTime = 'PGtimestamp+-- | `PGtimestamptz`+instance IsPG UTCTime where type PG UTCTime = 'PGtimestamptz+-- | `PGdate`+instance IsPG Day where type PG Day = 'PGdate+-- | `PGtime`+instance IsPG TimeOfDay where type PG TimeOfDay = 'PGtime+-- | `PGtimetz`+instance IsPG (TimeOfDay, TimeZone) where type PG (TimeOfDay, TimeZone) = 'PGtimetz+-- | `PGinterval`+instance IsPG DiffTime where type PG DiffTime = 'PGinterval+-- | `PGuuid`+instance IsPG UUID where type PG UUID = 'PGuuid+-- | `PGinet`+instance IsPG (NetAddr IP) where type PG (NetAddr IP) = 'PGinet+-- | `PGjson`+instance IsPG Value where type PG Value = 'PGjson+-- | `PGvarchar`+instance IsPG (VarChar n) where type PG (VarChar n) = 'PGvarchar n+-- | `PGvarchar`+instance IsPG (FixChar n) where type PG (FixChar n) = 'PGchar n++-- | `PGmoney`+instance IsPG Money where type PG Money = 'PGmoney+-- | `PGjson`+instance IsPG (Json hask) where type PG (Json hask) = 'PGjson+-- | `PGjsonb`+instance IsPG (Jsonb hask) where type PG (Jsonb hask) = 'PGjsonb+-- | `PGcomposite` @(@`RowPG` @hask)@+instance IsPG (Composite hask) where+ type PG (Composite hask) = 'PGcomposite (RowPG hask)+-- | `PGenum` @(@`LabelsPG` @hask)@+instance IsPG (Enumerated hask) where+ type PG (Enumerated hask) = 'PGenum (LabelsPG hask)+-- | `PGvararray` @(@`NullPG` @x)@+instance IsPG (VarArray (Vector x)) where+ type PG (VarArray (Vector x)) = 'PGvararray (NullPG x)+-- | `PGvararray` @(@`NullPG` @x)@+instance IsPG (VarArray [x]) where+ type PG (VarArray [x]) = 'PGvararray (NullPG x)+-- | `PGfixarray` @(@`DimPG` @hask) (@`FixPG` @hask)@+instance IsPG (FixArray hask) where+ type PG (FixArray hask) = 'PGfixarray (DimPG hask) (FixPG hask)++{-| The `LabelsPG` type family calculates the constructors of a+Haskell enum type.++>>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic+>>> instance SOP.Generic Schwarma+>>> instance SOP.HasDatatypeInfo Schwarma+>>> :kind! LabelsPG Schwarma+LabelsPG Schwarma :: [Type.ConstructorName]+= '["Beef", "Lamb", "Chicken"]+-}+type family LabelsPG (hask :: Type) :: [Type.ConstructorName] where+ LabelsPG hask =+ ConstructorNamesOf (ConstructorsOf (SOP.DatatypeInfoOf hask))++{- |+`RowPG` turns a Haskell `Type` into a `RowType`.++`RowPG` may be applied to normal Haskell record types provided they+have `SOP.Generic` and `SOP.HasDatatypeInfo` instances;++>>> data Person = Person { name :: Strict.Text, age :: Int32 } deriving GHC.Generic+>>> instance SOP.Generic Person+>>> instance SOP.HasDatatypeInfo Person+>>> :kind! RowPG Person+RowPG Person :: [(Symbol, NullType)]+= '["name" ::: 'NotNull 'PGtext, "age" ::: 'NotNull 'PGint4]+-}+type family RowPG (hask :: Type) :: RowType where+ RowPG hask = RowOf (SOP.RecordCodeOf hask)++-- | `RowOf` applies `NullPG` to the fields of a list.+type family RowOf (record :: [(Symbol, Type)]) :: RowType where+ RowOf (col ::: ty ': record) = col ::: NullPG ty ': RowOf record+ RowOf '[] = '[]++{- | `NullPG` turns a Haskell type into a `NullType`.++>>> :kind! NullPG Double+NullPG Double :: NullType+= 'NotNull 'PGfloat8+>>> :kind! NullPG (Maybe Double)+NullPG (Maybe Double) :: NullType+= 'Null 'PGfloat8+-}+type family NullPG (hask :: Type) :: NullType where+ NullPG (Maybe hask) = 'Null (PG hask)+ NullPG hask = 'NotNull (PG hask)++{- | `TuplePG` turns a Haskell tuple type (including record types) into+the corresponding list of `NullType`s.++>>> :kind! TuplePG (Double, Maybe Char)+TuplePG (Double, Maybe Char) :: [NullType]+= '[ 'NotNull 'PGfloat8, 'Null ('PGchar 1)]+-}+type family TuplePG (hask :: Type) :: [NullType] where+ TuplePG hask = TupleOf (TupleCodeOf hask (SOP.Code hask))++-- | `TupleOf` turns a list of Haskell `Type`s into a list of `NullType`s.+type family TupleOf (tuple :: [Type]) :: [NullType] where+ TupleOf (hask ': tuple) = NullPG hask ': TupleOf tuple+ TupleOf '[] = '[]++-- | `TupleCodeOf` takes the `SOP.Code` of a haskell `Type`+-- and if it's a simple product returns it, otherwise giving a `TypeError`.+type family TupleCodeOf (hask :: Type) (code :: [[Type]]) :: [Type] where+ TupleCodeOf hask '[tuple] = tuple+ TupleCodeOf hask '[] =+ TypeError+ ( 'Text "The type `" ':<>: 'ShowType hask ':<>: 'Text "' is not a tuple type."+ ':$$: 'Text "It is a void type with no constructors."+ )+ TupleCodeOf hask (_ ': _ ': _) =+ TypeError+ ( 'Text "The type `" ':<>: 'ShowType hask ':<>: 'Text "' is not a tuple type."+ ':$$: 'Text "It is a sum type with more than one constructor."+ )++-- | Calculates constructors of a datatype.+type family ConstructorsOf (datatype :: Type.DatatypeInfo)+ :: [Type.ConstructorInfo] where+#if MIN_VERSION_generics_sop(0,5,0)+ ConstructorsOf ('Type.ADT _module _datatype constructors _strictness) =+ constructors+#else+ ConstructorsOf ('Type.ADT _module _datatype constructors) =+ constructors+#endif+ ConstructorsOf ('Type.Newtype _module _datatype constructor) =+ '[constructor]++-- | Calculates the name of a nullary constructor, otherwise+-- generates a type error.+type family ConstructorNameOf (constructor :: Type.ConstructorInfo)+ :: Type.ConstructorName where+ ConstructorNameOf ('Type.Constructor name) = name+ ConstructorNameOf ('Type.Infix name _assoc _fix) = TypeError+ ('Text "ConstructorNameOf error: non-nullary constructor "+ ':<>: 'Text name)+ ConstructorNameOf ('Type.Record name _fields) = TypeError+ ('Text "ConstructorNameOf error: non-nullary constructor "+ ':<>: 'Text name)++-- | Calculate the names of nullary constructors.+type family ConstructorNamesOf (constructors :: [Type.ConstructorInfo])+ :: [Type.ConstructorName] where+ ConstructorNamesOf '[] = '[]+ ConstructorNamesOf (constructor ': constructors) =+ ConstructorNameOf constructor ': ConstructorNamesOf constructors++-- | `DimPG` turns Haskell nested homogeneous tuples into a list of lengths,+-- up to a depth of 10 for each dimension.+type family DimPG (hask :: Type) :: [Nat] where+ DimPG (x,x) = 2 ': DimPG x+ DimPG (x,x,x) = 3 ': DimPG x+ DimPG (x,x,x,x) = 4 ': DimPG x+ DimPG (x,x,x,x,x) = 5 ': DimPG x+ DimPG (x,x,x,x,x,x) = 6 ': DimPG x+ DimPG (x,x,x,x,x,x,x) = 7 ': DimPG x+ DimPG (x,x,x,x,x,x,x,x) = 8 ': DimPG x+ DimPG (x,x,x,x,x,x,x,x,x) = 9 ': DimPG x+ DimPG (x,x,x,x,x,x,x,x,x,x) = 10 ': DimPG x+ DimPG x = '[]++-- | `FixPG` extracts `NullPG` of the base type of nested homogeneous tuples,+-- up to a depth of 10 for each dimension.+type family FixPG (hask :: Type) :: NullType where+ FixPG (x,x) = FixPG x+ FixPG (x,x,x) = FixPG x+ FixPG (x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x,x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x,x,x,x,x,x) = FixPG x+ FixPG (x,x,x,x,x,x,x,x,x,x,x) = FixPG x+ FixPG x = NullPG x
+ src/Squeal/PostgreSQL/Type/Schema.hs view
@@ -0,0 +1,612 @@+{-|+Module: Squeal.PostgreSQL.Type.Schema+Description: Postgres type system+Copyright: (c) Eitan Chatav, 2019+Maintainer: eitan@morphism.tech+Stability: experimental++`Squeal.PostgreSQL.Type.Schema` provides a type-level DSL+for kinds of Postgres types, tables, schema, constraints, and more.+It also defines useful type families to operate on these.+-}++{-# LANGUAGE+ AllowAmbiguousTypes+ , ConstraintKinds+ , DeriveAnyClass+ , DeriveGeneric+ , FlexibleContexts+ , FlexibleInstances+ , FunctionalDependencies+ , GADTs+ , LambdaCase+ , OverloadedStrings+ , QuantifiedConstraints+ , RankNTypes+ , ScopedTypeVariables+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilyDependencies+ , TypeInType+ , TypeOperators+ , UndecidableInstances+ , UndecidableSuperClasses+#-}++module Squeal.PostgreSQL.Type.Schema+ ( -- * Postgres Type+ PGType (..)+ , NullType (..)+ , RowType+ , FromType+ -- * Schema Type+ , ColumnType+ , ColumnsType+ , TableType+ , SchemumType (..)+ , IndexType (..)+ , FunctionType+ , ReturnsType (..)+ , SchemaType+ , SchemasType+ , Public+ -- * Constraint+ , (:=>)+ , Optionality (..)+ , TableConstraint (..)+ , TableConstraints+ , Uniquely+ -- * Enumerated Label+ , IsPGlabel (..)+ , PGlabel (..)+ -- * Data Definition+ , Create+ , CreateIfNotExists+ , CreateOrReplace+ , Drop+ , DropSchemum+ , DropIfExists+ , DropSchemumIfExists+ , Alter+ , AlterIfExists+ , Rename+ , RenameIfExists+ , ConstraintInvolves+ , DropIfConstraintsInvolve+ -- * Type Classification+ , PGNum+ , PGIntegral+ , PGFloating+ , PGTypeOf+ , PGJsonType+ , PGJsonKey+ , SamePGType+ , AllNotNull+ , NotAllNull+ -- * Nullification+ , NullifyType+ , NullifyRow+ , NullifyFrom+ -- * Table Conversion+ , TableToColumns+ , ColumnsToRow+ , TableToRow+ -- * Updatable+ , Updatable+ , AllUnique+ , IsNotElem+ -- * User Types+ , UserType+ , UserTypeName+ , UserTypeNamespace+ ) where++import Control.Category+import Data.Kind+import Data.Monoid hiding (All)+import Data.Type.Bool+import Generics.SOP+import GHC.TypeLits+import Prelude hiding (id, (.))++import Squeal.PostgreSQL.Type.Alias+import Squeal.PostgreSQL.Type.List+import Squeal.PostgreSQL.Render++-- $setup+-- >>> import Squeal.PostgreSQL++-- | `PGType` is the promoted datakind of PostgreSQL types.+--+-- >>> :kind 'PGbool+-- 'PGbool :: PGType+data PGType+ = PGbool -- ^ logical Boolean (true/false)+ | PGint2 -- ^ signed two-byte integer+ | PGint4 -- ^ signed four-byte integer+ | PGint8 -- ^ signed eight-byte integer+ | PGnumeric -- ^ arbitrary precision numeric type+ | PGfloat4 -- ^ single precision floating-point number (4 bytes)+ | PGfloat8 -- ^ double precision floating-point number (8 bytes)+ | PGmoney -- ^ currency amount+ | PGchar Nat -- ^ fixed-length character string+ | PGvarchar Nat -- ^ variable-length character string+ | PGtext -- ^ variable-length character string+ | PGbytea -- ^ binary data ("byte array")+ | PGtimestamp -- ^ date and time (no time zone)+ | PGtimestamptz -- ^ date and time, including time zone+ | PGdate -- ^ calendar date (year, month, day)+ | PGtime -- ^ time of day (no time zone)+ | PGtimetz -- ^ time of day, including time zone+ | PGinterval -- ^ time span+ | PGuuid -- ^ universally unique identifier+ | PGinet -- ^ IPv4 or IPv6 host address+ | PGjson -- ^ textual JSON data+ | PGjsonb -- ^ binary JSON data, decomposed+ | PGvararray NullType -- ^ variable length array+ | PGfixarray [Nat] NullType -- ^ fixed length array+ | PGenum [Symbol] -- ^ enumerated (enum) types are data types that comprise a static, ordered set of values.+ | PGcomposite RowType -- ^ a composite type represents the structure of a row or record; it is essentially just a list of field names and their data types.+ | PGtsvector -- ^ A tsvector value is a sorted list of distinct lexemes, which are words that have been normalized to merge different variants of the same word.+ | PGtsquery -- ^ A tsquery value stores lexemes that are to be searched for.+ | PGoid -- Object identifiers (OIDs) are used internally by PostgreSQL as primary keys for various system tables.+ | PGrange PGType -- ^ Range types are data types representing a range of values of some element type (called the range's subtype).+ | UnsafePGType Symbol -- ^ an escape hatch for unsupported PostgreSQL types++-- | `NullType` encodes the potential presence or definite absence of a+-- @NULL@ allowing operations which are sensitive to such to be well typed.+--+-- >>> :kind 'Null 'PGint4+-- 'Null 'PGint4 :: NullType+-- >>> :kind 'NotNull ('PGvarchar 50)+-- 'NotNull ('PGvarchar 50) :: NullType+data NullType+ = Null PGType -- ^ @NULL@ may be present+ | NotNull PGType -- ^ @NULL@ is absent++-- | The constraint operator, `:=>` is a type level pair+-- between a "constraint" and some type, for use in pairing+-- an `Optionality` with a `NullType` to produce a `ColumnType`+-- or a `TableConstraints` and a `ColumnsType` to produce a `TableType`.+type (:=>) constraint ty = '(constraint,ty)+infixr 7 :=>++-- | `Optionality` encodes the availability of @DEFAULT@ for inserts and updates.+-- A column can be assigned a default value.+-- A data `Squeal.PostgreSQL.Manipulations.Manipulation` command can also+-- request explicitly that a column be set to its default value,+-- without having to know what that value is.+data Optionality+ = Def -- ^ @DEFAULT@ is available for inserts and updates+ | NoDef -- ^ @DEFAULT@ is unavailable for inserts and updates++-- | `ColumnType` encodes the allowance of @DEFAULT@ and @NULL@ and the+-- base `PGType` for a column.+--+-- >>> :set -XTypeFamilies -XTypeInType+-- >>> import GHC.TypeLits+-- >>> type family IdColumn :: ColumnType where IdColumn = 'Def :=> 'NotNull 'PGint4+-- >>> type family EmailColumn :: ColumnType where EmailColumn = 'NoDef :=> 'Null 'PGtext+type ColumnType = (Optionality,NullType)++-- | `ColumnsType` is a row of `ColumnType`s.+--+-- >>> :{+-- type family UsersColumns :: ColumnsType where+-- UsersColumns =+-- '[ "name" ::: 'NoDef :=> 'NotNull 'PGtext+-- , "id" ::: 'Def :=> 'NotNull 'PGint4+-- ]+-- :}+type ColumnsType = [(Symbol,ColumnType)]++-- | `TableConstraint` encodes various forms of data constraints+-- of columns in a table.+-- `TableConstraint`s give you as much control over the data in your tables+-- as you wish. If a user attempts to store data in a column that would+-- violate a constraint, an error is raised. This applies+-- even if the value came from the default value definition.+data TableConstraint+ = Check [Symbol]+ | Unique [Symbol]+ | PrimaryKey [Symbol]+ | ForeignKey [Symbol] Symbol [Symbol]++{- | A `TableConstraints` is a row of `TableConstraint`s.++>>> :{+type family UsersConstraints :: TableConstraints where+ UsersConstraints = '[ "pk_users" ::: 'PrimaryKey '["id"] ]+:}+-}+type TableConstraints = [(Symbol,TableConstraint)]++-- | A `ForeignKey` must reference columns that either are+-- a `PrimaryKey` or form a `Unique` constraint.+type family Uniquely+ (key :: [Symbol])+ (constraints :: TableConstraints) :: Constraint where+ Uniquely key (uq ::: 'Unique key ': constraints) = ()+ Uniquely key (pk ::: 'PrimaryKey key ': constraints) = ()+ Uniquely key (_ ': constraints) = Uniquely key constraints++-- | `TableType` encodes a row of constraints on a table as well as the types+-- of its columns.+--+-- >>> :{+-- type family UsersTable :: TableType where+-- UsersTable =+-- '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>+-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4+-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext+-- ]+-- :}+type TableType = (TableConstraints,ColumnsType)++{- | A `RowType` is a row of `NullType`. They correspond to Haskell+record types by means of `Squeal.PostgreSQL.Binary.RowPG` and are used in many places.++>>> :{+type family PersonRow :: RowType where+ PersonRow =+ '[ "name" ::: 'NotNull 'PGtext+ , "age" ::: 'NotNull 'PGint4+ , "dateOfBirth" ::: 'Null 'PGdate+ ]+:}+-}+type RowType = [(Symbol,NullType)]++{- | `FromType` is a row of `RowType`s. It can be thought of as+a product, or horizontal gluing and is used in `Squeal.PostgreSQL.Query.FromClause`s+and `Squeal.PostgreSQL.Query.TableExpression`s.+-}+type FromType = [(Symbol,RowType)]++-- | `ColumnsToRow` removes column constraints.+type family ColumnsToRow (columns :: ColumnsType) :: RowType where+ ColumnsToRow (column ::: _ :=> ty ': columns) =+ column ::: ty ': ColumnsToRow columns+ ColumnsToRow '[] = '[]++-- | `TableToColumns` removes table constraints.+type family TableToColumns (table :: TableType) :: ColumnsType where+ TableToColumns (constraints :=> columns) = columns++-- | Convert a table to a row type.+type family TableToRow (table :: TableType) :: RowType where+ TableToRow tab = ColumnsToRow (TableToColumns tab)++-- | Numeric Postgres types.+type PGNum =+ '[ 'PGint2, 'PGint4, 'PGint8, 'PGnumeric, 'PGfloat4, 'PGfloat8]++-- | Floating Postgres types.+type PGFloating = '[ 'PGfloat4, 'PGfloat8, 'PGnumeric]++-- | Integral Postgres types.+type PGIntegral = '[ 'PGint2, 'PGint4, 'PGint8]++-- | `PGTypeOf` forgets about @NULL@ and any column constraints.+type family PGTypeOf (ty :: NullType) :: PGType where+ PGTypeOf (null pg) = pg++-- | Equality constraint on the underlying `PGType` of two columns.+class SamePGType+ (ty0 :: (Symbol,ColumnType)) (ty1 :: (Symbol,ColumnType)) where+instance ty0 ~ ty1 => SamePGType+ (alias0 ::: def0 :=> null0 ty0)+ (alias1 ::: def1 :=> null1 ty1)++-- | `AllNotNull` is a constraint that proves a `ColumnsType` has no @NULL@s.+type family AllNotNull (columns :: ColumnsType) :: Constraint where+ AllNotNull (_ ::: _ :=> 'NotNull _ ': columns) = AllNotNull columns+ AllNotNull '[] = ()++-- | `NotAllNull` is a constraint that proves a `ColumnsType` has some+-- @NOT NULL@.+type family NotAllNull (columns :: ColumnsType) :: Constraint where+ NotAllNull (_ ::: _ :=> 'NotNull _ ': _) = ()+ NotAllNull (_ ::: _ :=> 'Null _ ': columns) = NotAllNull columns++-- | `NullifyType` is an idempotent that nullifies a `NullType`.+type family NullifyType (ty :: NullType) :: NullType where+ NullifyType ('Null ty) = 'Null ty+ NullifyType ('NotNull ty) = 'Null ty++-- | `NullifyRow` is an idempotent that nullifies a `RowType`.+type family NullifyRow (columns :: RowType) :: RowType where+ NullifyRow (column ::: ty ': columns) =+ column ::: NullifyType ty ': NullifyRow columns+ NullifyRow '[] = '[]++-- | `NullifyFrom` is an idempotent that nullifies a `FromType`+-- used to nullify the left or right hand side of an outer join+-- in a `Squeal.PostgreSQL.Query.FromClause`.+type family NullifyFrom (tables :: FromType) :: FromType where+ NullifyFrom (table ::: columns ': tables) =+ table ::: NullifyRow columns ': NullifyFrom tables+ NullifyFrom '[] = '[]++-- | @Create alias x xs@ adds @alias ::: x@ to the end of @xs@ and is used in+-- `Squeal.PostgreSQL.Definition.createTable` statements and in @ALTER TABLE@+-- `Squeal.PostgreSQL.Definition.addColumn`.+type family Create alias x xs where+ Create alias x '[] = '[alias ::: x]+ Create alias x (alias ::: y ': xs) = TypeError+ ('Text "Create: alias "+ ':<>: 'ShowType alias+ ':<>: 'Text "already exists")+ Create alias y (x ': xs) = x ': Create alias y xs++{-| Similar to `Create` but no error on pre-existence-}+type family CreateIfNotExists alias x xs where+ CreateIfNotExists alias x '[] = '[alias ::: x]+ CreateIfNotExists alias x (alias ::: y ': xs) = alias ::: y ': xs+ CreateIfNotExists alias y (x ': xs) = x ': CreateIfNotExists alias y xs++{-| Similar to `Create` but used to replace values+with the same type.-}+type family CreateOrReplace alias x xs where+ CreateOrReplace alias x '[] = '[alias ::: x]+ CreateOrReplace alias x (alias ::: x ': xs) = alias ::: x ': xs+ CreateOrReplace alias x (alias ::: y ': xs) = TypeError+ ('Text "CreateOrReplace: expected type "+ ':<>: 'ShowType x+ ':<>: 'Text " but alias "+ ':<>: 'ShowType alias+ ':<>: 'Text " has type "+ ':<>: 'ShowType y)+ CreateOrReplace alias y (x ': xs) = x ': CreateOrReplace alias y xs++-- | @Drop alias xs@ removes the type associated with @alias@ in @xs@+-- and is used in `Squeal.PostgreSQL.Definition.dropTable` statements+-- and in @ALTER TABLE@ `Squeal.PostgreSQL.Definition.dropColumn` statements.+type family Drop alias xs where+ Drop alias '[] = TypeError+ ('Text "Drop: alias "+ ':<>: 'ShowType alias+ ':<>: 'Text " does not exist" )+ Drop alias (alias ::: x ': xs) = xs+ Drop alias (x ': xs) = x ': Drop alias xs++-- | Drop a particular flavor of schemum type+type family DropSchemum alias sch xs where+ DropSchemum alias sch '[] = TypeError+ ('Text "DropSchemum: alias "+ ':<>: 'ShowType alias+ ':<>: 'Text " does not exist" )+ DropSchemum alias sch (alias ::: sch x ': xs) = xs+ DropSchemum alias sch0 (alias ::: sch1 x ': xs) = TypeError+ ('Text "DropSchemum: expected schemum "+ ':<>: 'ShowType sch0+ ':<>: 'Text " but alias "+ ':<>: 'ShowType alias+ ':<>: 'Text " has schemum "+ ':<>: 'ShowType sch1)+ DropSchemum alias sch (x ': xs) = x ': DropSchemum alias sch xs++-- | Similar to `Drop` but no error on non-existence+type family DropIfExists alias xs where+ DropIfExists alias '[] = '[]+ DropIfExists alias (alias ::: x ': xs) = xs+ DropIfExists alias (x ': xs) = x ': DropIfExists alias xs++-- | Similar to `DropSchemum` but no error on non-existence+type family DropSchemumIfExists alias sch xs where+ DropSchemumIfExists alias sch '[] = '[]+ DropSchemumIfExists alias sch (alias ::: sch x ': xs) = xs+ DropSchemumIfExists alias sch0 (alias ::: sch1 x ': xs) = TypeError+ ('Text "DropSchemumIfExists: expected schemum "+ ':<>: 'ShowType sch1+ ':<>: 'Text " but alias "+ ':<>: 'ShowType alias+ ':<>: 'Text " has schemum "+ ':<>: 'ShowType sch0)+ DropSchemumIfExists alias sch (x ': xs) = x ': DropSchemumIfExists alias sch xs++-- | @Alter alias x xs@ replaces the type associated with an @alias@ in @xs@+-- with the type @x@ and is used in `Squeal.PostgreSQL.Definition.alterTable`+-- and `Squeal.PostgreSQL.Definition.alterColumn`.+type family Alter alias x xs where+ Alter alias x '[] = TypeError+ ('Text "Alter: alias "+ ':<>: 'ShowType alias+ ':<>: 'Text " does not exist" )+ Alter alias x1 (alias ::: x0 ': xs) = alias ::: x1 ': xs+ Alter alias x1 (x0 ': xs) = x0 ': Alter alias x1 xs++-- | Similar to `Alter` but no error on non-existence+type family AlterIfExists alias x xs where+ AlterIfExists alias x '[] = '[]+ AlterIfExists alias x1 (alias ::: x0 ': xs) = alias ::: x1 ': xs+ AlterIfExists alias x1 (x0 ': xs) = x0 ': AlterIfExists alias x1 xs++-- | @Rename alias0 alias1 xs@ replaces the alias @alias0@ by @alias1@ in @xs@+-- and is used in `Squeal.PostgreSQL.Definition.alterTableRename` and+-- `Squeal.PostgreSQL.Definition.renameColumn`.+type family Rename alias0 alias1 xs where+ Rename alias0 alias1 '[] = TypeError+ ('Text "Rename: alias "+ ':<>: 'ShowType alias0+ ':<>: 'Text " does not exist" )+ Rename alias0 alias1 ((alias0 ::: x0) ': xs) = (alias1 ::: x0) ': xs+ Rename alias0 alias1 (x ': xs) = x ': Rename alias0 alias1 xs++-- | Similar to `Rename` but no error on non-existence+type family RenameIfExists alias0 alias1 xs where+ RenameIfExists alias x '[] = '[]+ RenameIfExists alias0 alias1 ((alias0 ::: x0) ': xs) = (alias1 ::: x0) ': xs+ RenameIfExists alias0 alias1 (x ': xs) = x ': RenameIfExists alias0 alias1 xs++-- | Check if a `TableConstraint` involves a column+type family ConstraintInvolves column constraint where+ ConstraintInvolves column ('Check columns) = column `Elem` columns+ ConstraintInvolves column ('Unique columns) = column `Elem` columns+ ConstraintInvolves column ('PrimaryKey columns) = column `Elem` columns+ ConstraintInvolves column ('ForeignKey columns tab refcolumns)+ = column `Elem` columns++-- | Drop all `TableConstraint`s that involve a column+type family DropIfConstraintsInvolve column constraints where+ DropIfConstraintsInvolve column '[] = '[]+ DropIfConstraintsInvolve column (alias ::: constraint ': constraints)+ = If (ConstraintInvolves column constraint)+ (DropIfConstraintsInvolve column constraints)+ (alias ::: constraint ': DropIfConstraintsInvolve column constraints)++-- | A `SchemumType` is a user-defined type, either a `Table`,+-- `View` or `Typedef`.+data SchemumType+ = Table TableType+ | View RowType+ | Typedef PGType+ | Index IndexType+ | Function FunctionType+ | UnsafeSchemum Symbol++-- | Use `:=>` to pair the parameter types with the return+-- type of a function.+type FunctionType = ([NullType], ReturnsType)++{- |+PostgreSQL provides several index types:+B-tree, Hash, GiST, SP-GiST, GIN and BRIN.+Each index type uses a different algorithm+that is best suited to different types of queries.+-}+data IndexType+ = Btree+ -- ^ B-trees can handle equality and range queries on data+ -- that can be sorted into some ordering.+ | Hash+ -- ^ Hash indexes can only handle simple equality comparisons.+ | Gist+ -- ^ GiST indexes are not a single kind of index,+ -- but rather an infrastructure within which many different+ -- indexing strategies can be implemented.+ | Spgist+ -- ^ SP-GiST indexes, like GiST indexes,+ -- offer an infrastructure that supports various kinds of searches.+ | Gin+ -- ^ GIN indexes are “inverted indexes” which are appropriate for+ -- data values that contain multiple component values, such as arrays.+ | Brin+ -- ^ BRIN indexes (a shorthand for Block Range INdexes) store summaries+ -- about the values stored in consecutive physical block ranges of a table.++{- | Return type of a function-}+data ReturnsType+ = Returns NullType -- ^ function+ | ReturnsTable RowType -- ^ set returning function++{- | The schema of a database consists of a list of aliased,+user-defined `SchemumType`s.++>>> :{+type family Schema :: SchemaType where+ Schema =+ '[ "users" ::: 'Table (+ '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext+ ])+ , "emails" ::: 'Table (+ '[ "pk_emails" ::: 'PrimaryKey '["id"]+ , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]+ ] :=>+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4+ , "email" ::: 'NoDef :=> 'Null 'PGtext+ ])+ ]+:}+-}+type SchemaType = [(Symbol,SchemumType)]++{- |+A database contains one or more named schemas, which in turn contain tables.+The same object name can be used in different schemas without conflict;+for example, both schema1 and myschema can contain tables named mytable.+Unlike databases, schemas are not rigidly separated:+a user can access objects in any of the schemas in the database they are connected to,+if they have privileges to do so.++There are several reasons why one might want to use schemas:++ * To allow many users to use one database without interfering with each other.+ * To organize database objects into logical groups to make them more manageable.+ * Third-party applications can be put into separate schemas+ so they do not collide with the names of other objects.+-}+type SchemasType = [(Symbol,SchemaType)]++-- | A type family to use for a single schema database.+type family Public (schema :: SchemaType) :: SchemasType+ where Public schema = '["public" ::: schema]++-- | `IsPGlabel` looks very much like the `IsLabel` class. Whereas+-- the overloaded label, `fromLabel` is used for column references,+-- `label`s are used for enum terms. A `label` is called with+-- type application like `label @"beef"`.+class IsPGlabel (label :: Symbol) expr where label :: expr+instance label ~ label1+ => IsPGlabel label (PGlabel label1) where label = PGlabel+instance labels ~ '[label]+ => IsPGlabel label (NP PGlabel labels) where label = PGlabel :* Nil+-- | A `PGlabel` unit type with an `IsPGlabel` instance+data PGlabel (label :: Symbol) = PGlabel+instance KnownSymbol label => RenderSQL (PGlabel label) where+ renderSQL _ = "\'" <> renderSymbol @label <> "\'"+instance All KnownSymbol labels => RenderSQL (NP PGlabel labels) where+ renderSQL+ = commaSeparated+ . hcollapse+ . hcmap (Proxy @KnownSymbol) (K . renderSQL)++-- | Is a type a valid JSON key?+type PGJsonKey = '[ 'PGint2, 'PGint4, 'PGtext ]++-- | Is a type a valid JSON type?+type PGJsonType = '[ 'PGjson, 'PGjsonb ]++-- | Utility class for `AllUnique` to provide nicer error messages.+class IsNotElem x isElem where+instance IsNotElem x 'False where+instance (TypeError ( 'Text "Cannot assign to "+ ':<>: 'ShowType alias+ ':<>: 'Text " more than once"))+ => IsNotElem '(alias, a) 'True where++-- | No elem of @xs@ appears more than once, in the context of assignment.+class AllUnique (xs :: [(Symbol, a)]) where+instance AllUnique '[] where+instance (IsNotElem x (Elem x xs), AllUnique xs) => AllUnique (x ': xs) where++-- | Updatable lists of columns+type Updatable table columns =+ ( All (HasIn (TableToColumns table)) columns+ , AllUnique columns+ , SListI (TableToColumns table) )++-- | Calculate the name of a user defined type.+type family UserTypeName (schema :: SchemaType) (ty :: PGType) where+ UserTypeName '[] ty = 'Nothing+ UserTypeName (td ::: 'Typedef ty ': _) ty = 'Just td+ UserTypeName (_ ': schema) ty = UserTypeName schema ty++-- | Helper to calculate the schema of a user defined type.+type family UserTypeNamespace+ (sch :: Symbol)+ (td :: Maybe Symbol)+ (schemas :: SchemasType)+ (ty :: PGType) where+ UserTypeNamespace sch 'Nothing schemas ty = UserType schemas ty+ UserTypeNamespace sch ('Just td) schemas ty = '(sch, td)++-- | Calculate the schema and name of a user defined type.+type family UserType (db :: SchemasType) (ty :: PGType) where+ UserType '[] ty = TypeError+ ('Text "No such user type: " ':<>: 'ShowType ty)+ UserType (sch ::: schema ': schemas) ty =+ UserTypeNamespace sch (UserTypeName schema ty) schemas ty
+ test/Doc.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Test.DocTest++main :: IO ()+main = doctest [ "-isrc", "src" ]
− test/DocTest.hs
@@ -1,18 +0,0 @@-module Main (main) where--import Test.DocTest--main :: IO ()-main = doctest- [ "-isrc"- , "src/Squeal/PostgreSQL.hs"- , "src/Squeal/PostgreSQL/Binary.hs"- , "src/Squeal/PostgreSQL/Definition.hs"- , "src/Squeal/PostgreSQL/Manipulation.hs"- , "src/Squeal/PostgreSQL/Query.hs"- , "src/Squeal/PostgreSQL/Expression.hs"- , "src/Squeal/PostgreSQL/PQ.hs"- , "src/Squeal/PostgreSQL/Migration.hs"- , "src/Squeal/PostgreSQL/Transaction.hs"- , "src/Squeal/PostgreSQL/Pool.hs"- ]
+ test/Property.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE+ DataKinds+ , FlexibleContexts+ , GADTs+ , LambdaCase+ , OverloadedLabels+ , OverloadedStrings+ , ScopedTypeVariables+ , TypeApplications+ , TypeOperators+#-}++module Main (main) where++import Control.Monad.Trans+import Data.ByteString (ByteString)+import Data.ByteString.Char8 (unpack)+import Data.Scientific (fromFloatDigits)+import Data.Fixed (Fixed(MkFixed), Micro, Pico)+import Data.String (IsString(fromString))+import Data.Time+import Hedgehog hiding (Range)+import Main.Utf8+import Squeal.PostgreSQL hiding (check)+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Main as Main+import qualified Hedgehog.Range as Range++main :: IO ()+main = withUtf8 $ Main.defaultMain [checkSequential roundtrips]++roundtrips :: Group+roundtrips = Group "roundtrips"+ [ roundtrip int2 genInt16+ , roundtrip int4 genInt32+ , roundtrip int8 genInt64+ , roundtrip bool Gen.bool+ , roundtrip numeric genScientific+ , roundtrip float4 genFloat+ , roundtrip float8 genDouble+ , roundtripOn normalizeAscii text genStringAscii+ , roundtripOn normalizeUtf8 text genStringUnicode+ -- , roundtripOn normalizeUtf8 text genStringAll+ , roundtripOn normalizeTimeOfDay time genTimeOfDay+ -- , roundtrip timetz genTimeWithZone+ , roundtripOn normalizeLocalTime timestamp genLocalTime+ , roundtrip timestamptz genUTCTime+ , roundtrip date genDay+ , roundtrip interval genDiffTime+ , roundtripOn normalizeIntRange int4range (genRange genInt32)+ , roundtripOn normalizeIntRange int8range (genRange genInt64)+ , roundtrip numrange (genRange genScientific)+ , roundtripOn (fmap normalizeLocalTime) tsrange (genRange genLocalTime)+ , roundtrip tstzrange (genRange genUTCTime)+ , roundtripOn normalizeIntRange daterange (genRange genDay)+ ]+ where+ genInt16 = Gen.int16 Range.exponentialBounded+ genInt32 = Gen.int32 Range.exponentialBounded+ genInt64 = Gen.int64 Range.exponentialBounded+ genScientific = fromFloatDigits <$> genFloat+ genPosFloat = Gen.float+ (Range.exponentialFloatFrom 1 minPosFloat maxPosFloat)+ genFloat = Gen.prune $ Gen.choice+ [ genPosFloat+ , negate <$> genPosFloat+ , Gen.element [0,1/0,-1/0]+ ]+ genPosDouble = Gen.double+ (Range.exponentialFloatFrom 1 minPosFloat maxPosFloat)+ genDouble = Gen.prune $ Gen.choice+ [ genPosDouble+ , negate <$> genPosDouble+ , Gen.element [0,1/0,-1/0]+ ]+ genStringAscii = Gen.string (Range.linear 0 100) Gen.ascii+ -- genStringLatin1 = Gen.string (Range.linear 0 100) Gen.latin1+ genStringUnicode = Gen.string (Range.linear 0 100) Gen.unicode+ -- genStringAll = Gen.string (Range.linear 0 100) Gen.unicodeAll+ genRange gen = do+ lb <- gen+ ub <- Gen.filter (lb <) gen+ Gen.element+ [ Empty, singleton lb, whole+ , lb <=..<= ub , lb <=..< ub, lb <..<= ub, lb <..< ub+ , atLeast lb, moreThan lb, atMost ub, lessThan ub ]+ genDay = do+ y <- toInteger <$> Gen.int (Range.constant 2000 2019)+ m <- Gen.int (Range.constant 1 12)+ d <- Gen.int (Range.constant 1 28)+ return $ fromGregorian y m d+ genDiffTime = do+ secs <- secondsToDiffTime . toInteger <$>+ Gen.int (Range.constant 0 86401)+ picos <- picosecondsToDiffTime . (* 1000000) . toInteger <$>+ Gen.int (Range.constant 0 (1000000 - 1))+ return $ secs + picos+ genUTCTime = UTCTime <$> genDay <*> genDiffTime+ genTimeOfDay = do+ h <- Gen.int (Range.constant 0 23)+ m <- Gen.int (Range.constant 0 59)+ s <- MkFixed . toInteger <$> Gen.int (Range.constant 0 59)+ return $ TimeOfDay h m s+ genLocalTime = LocalTime <$> genDay <*> genTimeOfDay+ -- genTimeZone = Gen.element $ map (read @TimeZone)+ -- [ "UTC", "UT", "GMT", "EST", "EDT", "CST"+ -- , "CDT", "MST", "MDT", "PST", "PDT" ]++roundtrip+ :: forall db x+ . ( ToPG db x, FromPG x, Inline x+ , OidOf db (PG x), PGTyped db (PG x)+ , Show x, Eq x )+ => TypeExpression db ('NotNull (PG x))+ -> Gen x+ -> (PropertyName, Property)+roundtrip = roundtripOn id++roundtripOn+ :: forall db x+ . ( ToPG db x, FromPG x, Inline x+ , OidOf db (PG x), PGTyped db (PG x)+ , Show x, Eq x )+ => (x -> x)+ -> TypeExpression db ('NotNull (PG x))+ -> Gen x+ -> (PropertyName, Property)+roundtripOn norm ty gen = propertyWithName $ do+ x <- forAll gen+ Just (Only y) <- lift . withConnection connectionString $+ firstRow =<< runQueryParams+ (values_ (parameter @1 ty `as` #fromOnly)) (Only x)+ Just (Only z) <- lift . withConnection connectionString $+ firstRow =<< runQuery+ (values_ (inline @x @'NotNull x `as` #fromOnly))+ y === z+ norm x === y+ where+ propertyWithName prop =+ (fromString (unpack (renderSQL ty)), property prop)++maxPosFloat :: RealFloat a => a+maxPosFloat = x+ where+ n = floatDigits x+ b = floatRadix x+ (_, u) = floatRange x+ x = encodeFloat (b^n - 1) (u - n)++minPosFloat :: RealFloat a => a+minPosFloat = x+ where+ n = floatDigits x+ b = floatRadix x+ (l, _) = floatRange x+ x = encodeFloat (b^n - 1) (l - n - 1)++connectionString :: ByteString+connectionString = "host=localhost port=5432 dbname=exampledb"++normalizeIntRange :: (Enum int, Ord int) => Range int -> Range int+normalizeIntRange = \case+ Empty -> Empty+ NonEmpty l u ->+ let+ l' = normalizeL l+ u' = normalizeU u+ in if emptyNormalized l' u' then Empty else NonEmpty l' u'+ where+ normalizeL = \case+ Open l -> Closed (succ l)+ normalized -> normalized+ normalizeU = \case+ Closed u -> Open (succ u)+ normalized -> normalized+ emptyNormalized (Closed l) (Open u) = l >= u+ emptyNormalized _ _ = False++normalizeTimeOfDay :: TimeOfDay -> TimeOfDay+normalizeTimeOfDay (TimeOfDay h m s) = TimeOfDay h m+ . fromRational @Pico+ . toRational @Micro+ . fromRational @Micro+ . toRational @Pico+ $ s++normalizeLocalTime :: LocalTime -> LocalTime+normalizeLocalTime (LocalTime d t) = LocalTime d (normalizeTimeOfDay t)++-- normalizeTimeWithZone :: (TimeOfDay, TimeZone) -> (TimeOfDay, TimeZone)+-- normalizeTimeWithZone (t, z) = (normalizeTimeOfDay t, z)++normalizeAscii :: String -> String+normalizeAscii = (stripped =<<)+ where+ stripped = \case+ '\NUL' -> ""+ ch -> [ch]++normalizeUtf8 :: String -> String+normalizeUtf8 = (stripped =<<)+ where+ stripped = \case+ '\NUL' -> ""+ ch -> [ch]
+ test/Spec.hs view
@@ -0,0 +1,212 @@+{-# LANGUAGE+ DataKinds+ , DeriveAnyClass+ , DeriveGeneric+ , DerivingStrategies+ , DerivingVia+ , DuplicateRecordFields+ , FlexibleContexts+ , FlexibleInstances+ , MultiParamTypeClasses+ , OverloadedLabels+ , OverloadedStrings+ , StandaloneDeriving+ , TypeApplications+ , TypeFamilies+ , TypeSynonymInstances+ , TypeInType+ , TypeOperators+ , UndecidableInstances+#-}++module Main (main) where++import Control.Concurrent.Async (replicateConcurrently)+import Data.ByteString (ByteString)+import Data.Int (Int32)+import Data.Text (Text)+import Test.Hspec++import qualified Data.ByteString.Char8 as Char8 (unlines)+import qualified Generics.SOP as SOP+import qualified GHC.Generics as GHC++import Squeal.PostgreSQL++main :: IO ()+main = hspec spec++type UsersConstraints =+ '[ "pk_users" ::: 'PrimaryKey '["id"]+ , "unique_names" ::: 'Unique '["name"] ]++type UsersColumns =+ '[ "id" ::: 'Def :=> 'NotNull 'PGint4+ , "name" ::: 'NoDef :=> 'NotNull 'PGtext ]++type Schema =+ '[ "users" ::: 'Table (UsersConstraints :=> UsersColumns)+ , "person" ::: 'Typedef (PG Person) ]++type DB = '[ "public" ::: Schema ]++data User = User+ { userName :: Text+ } deriving stock (Eq, Show, GHC.Generic)+ deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)++insertUser :: Manipulation_ DB User ()+insertUser = insertInto_ #users+ (Values_ (Default `as` #id :* Set (param @1) `as` #name))++setup :: Definition (Public '[]) DB+setup =+ createTable #users+ ( serial `as` #id :*+ notNullable text `as` #name )+ ( primaryKey #id `as` #pk_users :*+ unique #name `as` #unique_names ) >>>+ createTypeCompositeFrom @Person #person++teardown :: Definition DB (Public '[])+teardown = dropType #person >>> dropTable #users++silence :: MonadPQ db pq => pq ()+silence = manipulate_ $+ UnsafeManipulation "SET client_min_messages TO WARNING;"++setupDB :: IO ()+setupDB = withConnection connectionString $+ silence & pqThen (define setup)++dropDB :: IO ()+dropDB = withConnection connectionString $+ silence & pqThen (define teardown)++connectionString :: ByteString+connectionString = "host=localhost port=5432 dbname=exampledb"++data Person = Person { name :: Maybe String, age :: Maybe Int32 }+ deriving (Eq, Show, GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)+ deriving (IsPG, FromPG, ToPG db, Inline) via (Composite Person)++spec :: Spec+spec = before_ setupDB . after_ dropDB $ do++ describe "Exceptions" $ do++ let+ testUser = User "TestUser"+ newUser = manipulateParams_ insertUser+ insertUserTwice = newUser testUser >> newUser testUser+ err23505 = UniqueViolation $ Char8.unlines+ [ "ERROR: duplicate key value violates unique constraint \"unique_names\""+ , "DETAIL: Key (name)=(TestUser) already exists." ]++ it "should be thrown for constraint violation" $+ withConnection connectionString insertUserTwice+ `shouldThrow` (== err23505)++ it "should be rethrown for constraint violation in a transaction" $+ withConnection connectionString (transactionally_ insertUserTwice)+ `shouldThrow` (== err23505)++ describe "Pools" $++ it "should manage concurrent transactions" $ do+ pool <- createConnectionPool+ "host=localhost port=5432 dbname=exampledb" 1 0.5 10+ let+ qry :: Query_ (Public '[]) () (Only Char)+ qry = values_ (inline 'a' `as` #fromOnly)+ session = usingConnectionPool pool . transactionally_ $ do+ result <- runQuery qry+ Just (Only chr) <- firstRow result+ return chr+ chrs <- replicateConcurrently 10 session+ chrs `shouldSatisfy` all (== 'a')++ describe "Ranges" $++ it "should correctly decode ranges" $ do++ rangesOut <- withConnection connectionString $ do+ let+ qry :: Query_ (Public '[]) () (Only (Range Int32))+ qry = values+ ( range int4range (atLeast 3) `as` #fromOnly )+ [ range int4range (3 <=..< 5) `as` #fromOnly+ , range int4range Empty `as` #fromOnly+ , range int4range whole `as` #fromOnly ]+ getRows =<< runQuery qry+ (fromOnly <$> rangesOut :: [Range Int32]) `shouldBe`+ [ atLeast 3, 3 <=..< 5, Empty, whole ]++ describe "Parameters" $ do++ it "should run queries that don't reference all their parameters" $ do++ out <- withConnection connectionString $ do+ let+ qry :: Query_ (Public '[]) (Char,Int32) (Only Int32)+ qry = values_ (param @2 `as` #fromOnly)+ firstRow =<< runQueryParams qry ('a', 3 :: Int32)+ (fromOnly <$> out :: Maybe Int32) `shouldBe` Just 3++ describe "Composite types" $ do++ it "should be embeddible" $ do++ let++ roundtrip :: Query_ DB (Only Person) (Only Person)+ roundtrip = values_ (param @1 `as` #fromOnly)++ roundtrip_inline :: Person -> Query_ DB () (Only Person)+ roundtrip_inline person = values_ (inline person `as` #fromOnly)++ roundtrip_array :: Query_ DB+ (Only (VarArray [Person])) (Only (VarArray [Person]))+ roundtrip_array = values_ (param @1 `as` #fromOnly)++ oneway :: Query_ DB () (Only Person)+ oneway = values_ (row ("Adam" `as` #name :* 6000 `as` #age) `as` #fromOnly)++ oneway_array :: Query_ DB () (Only (VarArray [Person]))+ oneway_array = values_ $ array+ [ row ("Adam" `as` #name :* 6000 `as` #age)+ , row ("Lucy" `as` #name :* 2420000 `as` #age)+ ] `as` #fromOnly++ unsafeQ :: Query_ DB () (Only (VarArray [Composite Person]))+ unsafeQ = UnsafeQuery "select array[row(\'Adam\', 6000)]"++ nothingQ :: Query_ DB () (Only Person)+ nothingQ = values_ (row (null_ `as` #name :* null_ `as` #age) `as` #fromOnly)++ adam = Person (Just "Adam") (Just 6000)+ lucy = Person (Just "Lucy") (Just 2420000)+ people = VarArray [adam, lucy]++ out <- withConnection connectionString $+ firstRow =<< runQueryParams roundtrip (Only adam)+ out_inline <- withConnection connectionString $+ firstRow =<< runQuery (roundtrip_inline adam)+ out_array <- withConnection connectionString $+ firstRow =<< runQueryParams roundtrip_array (Only people)+ out2 <- withConnection connectionString $+ firstRow =<< runQuery oneway+ out2_array <- withConnection connectionString $+ firstRow =<< runQuery oneway_array+ unsafe_array <- withConnection connectionString $+ firstRow =<< runQuery unsafeQ+ nothings <- withConnection connectionString $+ firstRow =<< runQuery nothingQ++ out `shouldBe` Just (Only adam)+ out_inline `shouldBe` Just (Only adam)+ out_array `shouldBe` Just (Only people)+ out2 `shouldBe` Just (Only adam)+ out2_array `shouldBe` Just (Only people)+ unsafe_array `shouldBe` Just (Only (VarArray [Composite adam]))+ nothings `shouldBe` Just (Only (Person Nothing Nothing))
− test/Specs/ExceptionHandling.hs
@@ -1,140 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedLabels #-}-{-# LANGUAGE OverloadedLists #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-module ExceptionHandling- ( specs- , User (..)- ) where--import Control.Concurrent.Async (replicateConcurrently)-import Control.Monad (void)-import Control.Monad.IO.Class (MonadIO (..))-import Data.Int (Int16)-import Data.Text (Text)-import Data.Vector (Vector)-import Test.Hspec--import qualified Data.ByteString.Char8 as Char8-import qualified Generics.SOP as SOP-import qualified GHC.Generics as GHC--import Squeal.PostgreSQL--type Schema =- '[ "users" ::: 'Table (- '[ "pk_users" ::: 'PrimaryKey '["id"]- , "unique_names" ::: 'Unique '["name"]- ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "name" ::: 'NoDef :=> 'NotNull 'PGtext- , "vec" ::: 'NoDef :=> 'NotNull ('PGvararray ('Null 'PGint2))- ])- , "emails" ::: 'Table (- '[ "pk_emails" ::: 'PrimaryKey '["id"]- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]- ] :=>- '[ "id" ::: 'Def :=> 'NotNull 'PGint4- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4- , "email" ::: 'NoDef :=> 'Null 'PGtext- ])- ]--type Schemas = Public Schema--data User =- User { userName :: Text- , userEmail :: Maybe Text- , userVec :: VarArray (Vector (Maybe Int16)) }- deriving (Show, GHC.Generic)-instance SOP.Generic User-instance SOP.HasDatatypeInfo User--insertUser :: Manipulation '[] Schemas '[ 'NotNull 'PGtext, 'NotNull ('PGvararray ('Null 'PGint2))]- '[ "fromOnly" ::: 'NotNull 'PGint4 ]-insertUser = insertInto #users- (Values_ (Default `as` #id :* Set (param @1) `as` #name :* Set (param @2) `as` #vec))- OnConflictDoRaise (Returning (#id `as` #fromOnly))--setup :: Definition (Public '[]) Schemas-setup =- createTable #users- ( serial `as` #id :*- (text & notNullable) `as` #name :*- (vararray int2 & notNullable) `as` #vec )- ( primaryKey #id `as` #pk_users- :* unique #name `as` #unique_names )- >>>- createTable #emails- ( serial `as` #id :*- (int & notNullable) `as` #user_id :*- (text & nullable) `as` #email )- ( primaryKey #id `as` #pk_emails :*- foreignKey #user_id #users #id- OnDeleteCascade OnUpdateCascade `as` #fk_user_id )--teardown :: Definition Schemas (Public '[])-teardown = dropTable #emails >>> dropTable #users--migration :: Migration Definition (Public '[]) Schemas-migration = Migration { name = "test"- , up = setup- , down = teardown }--setupDB :: IO ()-setupDB = withConnection connectionString $- manipulate (UnsafeManipulation "SET client_min_messages TO WARNING;")- & pqThen (migrateUp (single migration))--dropDB :: IO ()-dropDB = withConnection connectionString $- manipulate (UnsafeManipulation "SET client_min_messages TO WARNING;")- & pqThen (migrateDown (single migration))--connectionString :: Char8.ByteString-connectionString = "host=localhost port=5432 dbname=exampledb"--testUser :: User-testUser = User "TestUser" Nothing (VarArray [])--newUser :: (MonadIO m, MonadPQ Schemas m) => User -> m ()-newUser u = void $ manipulateParams insertUser (userName u, userVec u)--insertUserTwice :: (MonadIO m, MonadPQ Schemas m) => m ()-insertUserTwice = newUser testUser >> newUser testUser--specs :: SpecWith ()-specs = before_ setupDB $ after_ dropDB $- describe "Exceptions" $ do-- let- dupKeyErr = PQException $ PQState FatalError (Just "23505")- (Just "ERROR: duplicate key value violates unique constraint \"unique_names\"\nDETAIL: Key (name)=(TestUser) already exists.\n")-- it "should be thrown for unique constraint violation in a manipulation" $- withConnection connectionString insertUserTwice- `shouldThrow` (== dupKeyErr)-- it "should be rethrown for unique constraint violation in a manipulation by a transaction" $- withConnection connectionString (transactionally_ insertUserTwice)- `shouldThrow` (== dupKeyErr)-- it "should handle concurrent transactions using pooled connections" $ do- pool <- createConnectionPool- "host=localhost port=5432 dbname=exampledb" 1 0.5 10- let- query :: Query_ (Public '[]) () (Only Char)- query = values_ (literal 'a' `as` #fromOnly)- session = usingConnectionPool pool . transactionally_ $ do- result <- runQuery query- Just (Only chr) <- firstRow result- return chr- chrs <- replicateConcurrently 10 session- chrs `shouldSatisfy` (all (== 'a'))
− test/Specs/Specs.hs
@@ -1,7 +0,0 @@-module Main where--import Test.Hspec-import qualified ExceptionHandling--main :: IO ()-main = hspec ExceptionHandling.specs