-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Squeal PostgreSQL Library -- -- Squeal is a type-safe embedding of PostgreSQL in Haskell @package squeal-postgresql @version 0.5.1.0 -- | Rendering helper functions. module Squeal.PostgreSQL.Render -- | A class for rendering SQL class RenderSQL sql renderSQL :: RenderSQL sql => sql -> ByteString -- | Print SQL. printSQL :: (RenderSQL sql, MonadIO io) => sql -> io () -- | escape a character to prevent injection escape :: Char -> String -- | Parenthesize a ByteString. parenthesized :: ByteString -> ByteString -- | Square bracket a ByteString bracketed :: ByteString -> ByteString -- | Concatenate two ByteStrings with a space between. (<+>) :: ByteString -> ByteString -> ByteString infixr 7 <+> -- | Comma separate a list of ByteStrings. commaSeparated :: [ByteString] -> ByteString -- | Add double quotes around a ByteString. doubleQuoted :: ByteString -> ByteString -- | Add single quotes around a Text and escape single quotes within -- it. singleQuotedText :: Text -> ByteString -- | Add single quotes around a ByteString and escape single quotes -- within it. singleQuotedUtf8 :: ByteString -> ByteString -- | Comma separate the renderings of a heterogeneous list. renderCommaSeparated :: SListI xs => (forall x. expression x -> ByteString) -> NP expression xs -> ByteString -- | Comma separate the renderings of a heterogeneous list. renderCommaSeparatedConstraint :: forall c xs expression. (All c xs, SListI xs) => (forall x. c x => expression x -> ByteString) -> NP expression xs -> ByteString -- | Comma separate the Maybe renderings of a heterogeneous list, -- dropping Nothings. renderCommaSeparatedMaybe :: SListI xs => (forall x. expression x -> Maybe ByteString) -> NP expression xs -> ByteString -- | Render a promoted Nat. renderNat :: forall n. KnownNat n => ByteString -- | Render a promoted Symbol. renderSymbol :: forall s. KnownSymbol s => ByteString -- | Haskell singly-linked lists are very powerful. This module provides -- functionality for type-level lists, heterogeneous lists and type -- aligned lists. module Squeal.PostgreSQL.List -- | An n-ary product. -- -- The product is parameterized by a type constructor f and -- indexed by a type-level list xs. The length of the list -- determines the number of elements in the product, and if the -- i-th element of the list is of type x, then the -- i-th element of the product is of type f x. -- -- The constructor names are chosen to resemble the names of the list -- constructors. -- -- Two common instantiations of f are the identity functor -- I and the constant functor K. For I, the product -- becomes a heterogeneous list, where the type-level list describes the -- types of its components. For K a, the product becomes -- a homogeneous list, where the contents of the type-level list are -- ignored, but its length still specifies the number of elements. -- -- In the context of the SOP approach to generic programming, an n-ary -- product describes the structure of the arguments of a single data -- constructor. -- -- Examples: -- --
-- I 'x' :* I True :* Nil :: NP I '[ Char, Bool ] -- K 0 :* K 1 :* Nil :: NP (K Int) '[ Char, Bool ] -- Just 'x' :* Nothing :* Nil :: NP Maybe '[ Char, Bool ] --data NP (a :: k -> Type) (b :: [k]) :: forall k. () => k -> Type -> [k] -> Type [Nil] :: forall k (a :: k -> Type) (b :: [k]). () => NP a ([] :: [k]) [:*] :: forall k (a :: k -> Type) (b :: [k]) (x :: k) (xs :: [k]). () => a x -> NP a xs -> NP a (x : xs) infixr 5 :* -- | A useful operator for ending an NP list of length at least 2 -- without Nil. (*:) :: f x -> f y -> NP f '[x, y] infixl 9 *: -- | Join is simply promoted ++ and is used in JOINs -- in FromClauses. type family 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) -- | The Additional class is for appending type-level list -- parameterized constructors such as NP, Selection, and -- FromClause. class Additional expr also :: Additional expr => expr ys -> expr xs -> expr (Join xs ys) -- | An AlignedList is a type-aligned list or free category. data AlignedList p x0 x1 [Done] :: AlignedList p x x [:>>] :: p x0 x1 -> AlignedList p x1 x2 -> AlignedList p x0 x2 infixr 7 :>> -- | A single step. single :: p x0 x1 -> AlignedList p x0 x1 -- | extractList turns an AlignedList into a standard list. extractList :: (forall a0 a1. p a0 a1 -> b) -> AlignedList p x0 x1 -> [b] -- | 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 -- | Elem is a promoted elem. type family Elem x xs -- | In x xs is a constraint that proves that x is in -- xs. type family In x xs :: Constraint -- | 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 instance forall k (p :: k -> k -> *). Control.Category.Category (Squeal.PostgreSQL.List.AlignedList p) 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) instance forall a (expr :: a -> *). Squeal.PostgreSQL.List.Additional (Data.SOP.NP.NP expr) -- | 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 #. module Squeal.PostgreSQL.Alias -- | 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 ::: -- | Aliases 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 :: Alias class IsLabel (x :: Symbol) a fromLabel :: IsLabel x a => a -- | 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
[As] :: KnownSymbol alias => expression ty -> Alias alias -> Aliased expression (alias ::: ty)
-- | The Aliasable class provides a way to scrap your Nils in
-- an NP list of Aliased expressions.
class KnownSymbol alias => Aliasable alias expression aliased | aliased -> expression, aliased -> alias
as :: Aliasable alias expression aliased => expression -> Alias alias -> aliased
-- | -- >>> 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 -- | 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 -- | 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] -- | HasAll extends Has to take lists of aliases and -- fields and infer a list of subfields. class (All KnownSymbol aliases) => HasAll (aliases :: [Symbol]) (fields :: [(Symbol, kind)]) (subfields :: [(Symbol, kind)]) | aliases fields -> subfields -- | HasIn fields (alias ::: field) is a constraint that proves -- that fields has a field of alias ::: field. It is -- used in UPDATEs to choose which subfields to update. class HasIn fields field -- | QualifiedAliases enables multi-schema support by allowing a -- reference to a Table, Typedef or 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 :: QualifiedAlias
-- | Analagous to IsLabel, the constraint IsQualified defines
-- ! for a column alias qualified by a table alias.
class IsQualified table column expression
(!) :: IsQualified table column expression => Alias table -> Alias column -> expression
infixl 9 !
-- | Grouping is an auxiliary namespace, created by GROUP
-- BY clauses (group), and used for typesafe aggregation
data Grouping
-- | no aggregation permitted
Ungrouped :: Grouping
-- | aggregation required for any column which is not grouped
Grouped :: [(Symbol, Symbol)] -> Grouping
-- | 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 Expression without
-- aggregating.
class (KnownSymbol table, KnownSymbol column) => GroupedBy table column bys
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
instance GHC.Show.Show (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Alias.QualifiedAlias qualifier alias)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Alias.Alias alias)
instance GHC.Show.Show (Squeal.PostgreSQL.Alias.Alias alias)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Alias.Alias alias)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Alias.Alias alias)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Alias.Alias 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))
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))
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))
instance (q Data.Type.Equality.~ q', a Data.Type.Equality.~ a') => Squeal.PostgreSQL.Alias.IsQualified q a (Squeal.PostgreSQL.Alias.QualifiedAlias q' a')
instance (q' Data.Type.Equality.~ "public", a Data.Type.Equality.~ a') => GHC.OverloadedLabels.IsLabel a (Squeal.PostgreSQL.Alias.QualifiedAlias q' a')
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))
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))
instance (GHC.TypeLits.KnownSymbol q, GHC.TypeLits.KnownSymbol a) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Alias.QualifiedAlias q a)
instance Squeal.PostgreSQL.Alias.IsQualified table column (Squeal.PostgreSQL.Alias.Alias table, Squeal.PostgreSQL.Alias.Alias column)
instance forall kind (fields :: [(GHC.Types.Symbol, kind)]). Squeal.PostgreSQL.Alias.HasAll '[] fields '[]
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)
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)
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
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
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)
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)
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))
instance (alias1 Data.Type.Equality.~ alias2) => GHC.OverloadedLabels.IsLabel alias1 (Squeal.PostgreSQL.Alias.Alias alias2)
instance (aliases Data.Type.Equality.~ '[alias]) => GHC.OverloadedLabels.IsLabel alias (Data.SOP.NP.NP Squeal.PostgreSQL.Alias.Alias aliases)
instance GHC.TypeLits.KnownSymbol alias => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Alias.Alias alias)
instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol aliases => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Alias.Alias aliases)
instance (GHC.TypeLits.KnownSymbol table, GHC.TypeLits.KnownSymbol column) => Squeal.PostgreSQL.Alias.GroupedBy table column ('(table, column) : bys)
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)
-- | 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.
module Squeal.PostgreSQL.Schema
-- | PGType is the promoted datakind of PostgreSQL types.
--
-- -- >>> :kind 'PGbool -- 'PGbool :: PGType --data PGType -- | logical Boolean (true/false) PGbool :: PGType -- | signed two-byte integer PGint2 :: PGType -- | signed four-byte integer PGint4 :: PGType -- | signed eight-byte integer PGint8 :: PGType -- | arbitrary precision numeric type PGnumeric :: PGType -- | single precision floating-point number (4 bytes) PGfloat4 :: PGType -- | double precision floating-point number (8 bytes) PGfloat8 :: PGType -- | currency amount PGmoney :: PGType -- | fixed-length character string PGchar :: Nat -> PGType -- | variable-length character string PGvarchar :: Nat -> PGType -- | variable-length character string PGtext :: PGType -- | binary data ("byte array") PGbytea :: PGType -- | date and time (no time zone) PGtimestamp :: PGType -- | date and time, including time zone PGtimestamptz :: PGType -- | calendar date (year, month, day) PGdate :: PGType -- | time of day (no time zone) PGtime :: PGType -- | time of day, including time zone PGtimetz :: PGType -- | time span PGinterval :: PGType -- | universally unique identifier PGuuid :: PGType -- | IPv4 or IPv6 host address PGinet :: PGType -- | textual JSON data PGjson :: PGType -- | binary JSON data, decomposed PGjsonb :: PGType -- | variable length array PGvararray :: NullityType -> PGType -- | fixed length array PGfixarray :: [Nat] -> NullityType -> PGType -- | enumerated (enum) types are data types that comprise a static, ordered -- set of values. PGenum :: [Symbol] -> PGType -- | a composite type represents the structure of a row or record; it is -- essentially just a list of field names and their data types. PGcomposite :: RowType -> PGType -- | 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. PGtsvector :: PGType -- | A tsquery value stores lexemes that are to be searched for PGtsquery :: PGType -- | an escape hatch for unsupported PostgreSQL types UnsafePGType :: Symbol -> PGType -- | 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 may be present
Null :: PGType -> NullityType
-- | NULL is absent
NotNull :: PGType -> NullityType
-- | A RowType is a row of NullityType. They correspond to
-- Haskell record types by means of 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 RowTypes. It can be thought of as a
-- product, or horizontal gluing and is used in FromClauses and
-- TableExpressions.
type FromType = [(Symbol, RowType)]
-- | 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 ColumnTypes. -- --
-- >>> :{
-- type family UsersColumns :: ColumnsType where
-- UsersColumns =
-- '[ "name" ::: 'NoDef :=> 'NotNull 'PGtext
-- , "id" ::: 'Def :=> 'NotNull 'PGint4
-- ]
-- :}
--
type ColumnsType = [(Symbol, ColumnType)]
-- | 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 SchemumType is a user-defined type, either a Table,
-- View or Typedef.
data SchemumType
Table :: TableType -> SchemumType
View :: RowType -> SchemumType
Typedef :: PGType -> SchemumType
-- | The schema of a database consists of a list of aliased, user-defined
-- SchemumTypes.
--
--
-- >>> :{
-- 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:
--
--
-- >>> :{
-- 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
-- | IsPGlabel looks very much like the IsLabel class.
-- Whereas the overloaded label, fromLabel is used for column
-- references, labels are used for enum terms. A label is
-- called with type application like `label @"beef"`.
class IsPGlabel (label :: Symbol) expr
label :: IsPGlabel label expr => expr
-- | A PGlabel unit type with an IsPGlabel instance
data PGlabel (label :: Symbol)
PGlabel :: PGlabel
-- | Create alias x xs adds alias ::: x to the end of
-- xs and is used in createTable statements and in
-- ALTER TABLE addColumn.
type family Create alias x xs
-- | Drop alias xs removes the type associated with alias
-- in xs and is used in dropTable statements and in
-- ALTER TABLE dropColumn statements.
type family Drop alias xs
-- | Alter alias x xs replaces the type associated with an
-- alias in xs with the type x and is used in
-- alterTable and alterColumn.
type family Alter alias x xs
-- | Rename alias0 alias1 xs replaces the alias alias0 by
-- alias1 in xs and is used in alterTableRename
-- and renameColumn.
type family Rename alias0 alias1 xs
-- | Check if a TableConstraint involves a column
type family ConstraintInvolves column constraint
-- | Drop all TableConstraints that involve a column
type family DropIfConstraintsInvolve column constraints
-- | Utility class for AllUnique to provide nicer error messages.
class IsNotElem x isElem
-- | No elem of xs appears more than once, in the context of
-- assignment.
class AllUnique (xs :: [(Symbol, a)])
-- | Numeric Postgres types.
type PGNum = '[ 'PGint2, 'PGint4, 'PGint8, 'PGnumeric, 'PGfloat4, 'PGfloat8]
-- | Integral Postgres types.
type PGIntegral = '[ 'PGint2, 'PGint4, 'PGint8]
-- | Floating Postgres types.
type PGFloating = '[ 'PGfloat4, 'PGfloat8, 'PGnumeric]
-- | PGTypeOf forgets about NULL and any column
-- constraints.
type family PGTypeOf (ty :: NullityType) :: PGType
-- | Is a type a valid JSON type?
type PGJsonType = '[ 'PGjson, 'PGjsonb]
-- | Is a type a valid JSON key?
type PGJsonKey = '[ 'PGint2, 'PGint4, 'PGtext]
-- | Equality constraint on the underlying PGType of two columns.
class SamePGType (ty0 :: (Symbol, ColumnType)) (ty1 :: (Symbol, ColumnType))
-- | AllNotNull is a constraint that proves a ColumnsType has
-- no NULLs.
type family AllNotNull (columns :: ColumnsType) :: Constraint
-- | NotAllNull is a constraint that proves a ColumnsType has
-- some NOT NULL.
type family NotAllNull (columns :: ColumnsType) :: Constraint
-- | NullifyType is an idempotent that nullifies a
-- NullityType.
type family NullifyType (ty :: NullityType) :: NullityType
-- | NullifyRow is an idempotent that nullifies a RowType.
type family NullifyRow (columns :: RowType) :: RowType
-- | NullifyFrom is an idempotent that nullifies a FromType
-- used to nullify the left or right hand side of an outer join in a
-- FromClause.
type family NullifyFrom (tables :: FromType) :: FromType
-- | TableToColumns removes table constraints.
type family TableToColumns (table :: TableType) :: ColumnsType
-- | ColumnsToRow removes column constraints.
type family ColumnsToRow (columns :: ColumnsType) :: RowType
-- | Convert a table to a row type.
type family TableToRow (table :: TableType) :: RowType
instance Squeal.PostgreSQL.Schema.AllUnique '[]
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)
instance forall k (x :: k). Squeal.PostgreSQL.Schema.IsNotElem x 'GHC.Types.False
instance forall k1 k2 (alias :: k2) (a :: k1). (TypeError ...) => Squeal.PostgreSQL.Schema.IsNotElem '(alias, a) 'GHC.Types.True
instance (label Data.Type.Equality.~ label1) => Squeal.PostgreSQL.Schema.IsPGlabel label (Squeal.PostgreSQL.Schema.PGlabel label1)
instance (labels Data.Type.Equality.~ '[label]) => Squeal.PostgreSQL.Schema.IsPGlabel label (Data.SOP.NP.NP Squeal.PostgreSQL.Schema.PGlabel labels)
instance GHC.TypeLits.KnownSymbol label => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Schema.PGlabel label)
instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol labels => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Schema.PGlabel labels)
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))
-- | PG provides type families for turning Haskell Types into
-- corresponding Postgres types.
module Squeal.PostgreSQL.PG
-- | 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 -- | 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 -- | TuplePG turns a Haskell tuple type (including record types) -- into the corresponding list of NullityTypes. -- --
-- >>> :kind! TuplePG (Double, Maybe Char)
-- TuplePG (Double, Maybe Char) :: [NullityType]
-- = '[ 'NotNull 'PGfloat8, 'Null ('PGchar 1)]
--
type family TuplePG (hask :: Type) :: [NullityType]
-- | RowPG turns a Haskell Type into a RowType.
--
-- RowPG may be applied to normal Haskell record types provided
-- they have Generic and 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
-- | 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 :: Int64 -> Money
[cents] :: Money -> Int64
-- | The Json newtype is an indication that the Haskell type it's
-- applied to should be stored as a PGjson.
newtype Json hask
Json :: hask -> Json hask
[getJson] :: Json hask -> hask
-- | The Jsonb newtype is an indication that the Haskell type it's
-- applied to should be stored as a PGjsonb.
newtype Jsonb hask
Jsonb :: hask -> Jsonb hask
[getJsonb] :: Jsonb hask -> hask
-- | The Composite newtype is an indication that the Haskell type
-- it's applied to should be stored as a PGcomposite.
newtype Composite record
Composite :: record -> Composite record
[getComposite] :: Composite record -> record
-- | The Enumerated newtype is an indication that the Haskell type
-- it's applied to should be stored as a PGenum.
newtype Enumerated enum
Enumerated :: enum -> Enumerated enum
[getEnumerated] :: Enumerated enum -> enum
-- | 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 :: arr -> VarArray arr
[getVarArray] :: VarArray arr -> arr
-- | 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 :: arr -> FixArray arr
[getFixArray] :: FixArray arr -> arr
-- | 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) :: [ConstructorName] -- | DimPG turns Haskell nested homogeneous tuples into a list of -- lengths. type family DimPG (hask :: Type) :: [Nat] -- | FixPG extracts NullPG of the base type of nested -- homogeneous tuples. type family FixPG (hask :: Type) :: NullityType -- | TupleOf turns a list of Haskell Types into a list of -- NullityTypes. type family TupleOf (tuple :: [Type]) :: [NullityType] -- | TupleCodeOf takes the 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] -- | RowOf applies NullPG to the fields of a list. type family RowOf (record :: [(Symbol, Type)]) :: RowType -- | Calculates constructors of a datatype. type family ConstructorsOf (datatype :: DatatypeInfo) :: [ConstructorInfo] -- | Calculates the name of a nullary constructor, otherwise generates a -- type error. type family ConstructorNameOf (constructor :: ConstructorInfo) :: ConstructorName -- | Calculate the names of nullary constructors. type family ConstructorNamesOf (constructors :: [ConstructorInfo]) :: [ConstructorName] instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.FixArray arr) instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.PG.FixArray arr) instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.PG.FixArray arr) instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.PG.FixArray arr) instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.PG.FixArray arr) instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.VarArray arr) instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.PG.VarArray arr) instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.PG.VarArray arr) instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.PG.VarArray arr) instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.PG.VarArray arr) instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Enumerated enum) instance GHC.Read.Read enum => GHC.Read.Read (Squeal.PostgreSQL.PG.Enumerated enum) instance GHC.Show.Show enum => GHC.Show.Show (Squeal.PostgreSQL.PG.Enumerated enum) instance GHC.Classes.Ord enum => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Enumerated enum) instance GHC.Classes.Eq enum => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Enumerated enum) instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Composite record) instance GHC.Read.Read record => GHC.Read.Read (Squeal.PostgreSQL.PG.Composite record) instance GHC.Show.Show record => GHC.Show.Show (Squeal.PostgreSQL.PG.Composite record) instance GHC.Classes.Ord record => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Composite record) instance GHC.Classes.Eq record => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Composite record) instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Jsonb hask) instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.PG.Jsonb hask) instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.PG.Jsonb hask) instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Jsonb hask) instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Jsonb hask) instance GHC.Generics.Generic (Squeal.PostgreSQL.PG.Json hask) instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.PG.Json hask) instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.PG.Json hask) instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.PG.Json hask) instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.PG.Json hask) instance GHC.Generics.Generic Squeal.PostgreSQL.PG.Money instance GHC.Read.Read Squeal.PostgreSQL.PG.Money instance GHC.Show.Show Squeal.PostgreSQL.PG.Money instance GHC.Classes.Ord Squeal.PostgreSQL.PG.Money instance GHC.Classes.Eq Squeal.PostgreSQL.PG.Money -- | Squeal expressions are the atoms used to build statements. module Squeal.PostgreSQL.Expression -- | Expressions are used in a variety of contexts, such as in the -- target List of the select command, as new column values -- in insertRow or update, or in search Conditions -- in a number of commands. -- -- The expression syntax allows the calculation of values from primitive -- expression using arithmetic, logical, and other operations. -- -- The type parameters of Expression are -- --
-- >>> printSQL $ unsafeFunction "f" true -- f(TRUE) --unsafeFunction :: ByteString -> x :--> y -- |
-- >>> printSQL $ unsafeUnaryOpL "NOT" true -- (NOT TRUE) --unsafeUnaryOpL :: ByteString -> x :--> y -- |
-- >>> printSQL $ true & unsafeUnaryOpR "IS NOT TRUE" -- (TRUE IS NOT TRUE) --unsafeUnaryOpR :: ByteString -> x :--> y -- | 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 " left input" -> Expression outer commons grp schemas params from x2 " right input" -> Expression outer commons grp schemas params from y " output" -- |
-- >>> printSQL $ unsafeBinaryOp "OR" true false -- (TRUE OR FALSE) --unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2 -- | 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] " inputs" -> Expression outer commons grp schemas params from x1 " must have at least 1 input" -> Expression outer commons grp schemas params from y " output" -- |
-- >>> printSQL (unsafeFunctionVar "greatest" [true, null_] false) -- greatest(TRUE, NULL, FALSE) --unsafeFunctionVar :: ByteString -> FunctionVar x0 x1 y -- | A RankNType for functions with a fixed-length list of -- heterogeneous arguments. Use the *: operator to end your -- argument lists, like so. -- --
-- >>> 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 " inputs" -> Expression outer commons grp schemas params from y " output" -- |
-- >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: literal 'a') -- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, E'a') --unsafeFunctionN :: SListI xs => ByteString -> FunctionN xs y -- | Contained by operators class PGSubset container (@>) :: PGSubset container => Operator (null0 container) (null1 container) ( 'Null 'PGbool) (<@) :: PGSubset container => Operator (null0 container) (null1 container) ( 'Null 'PGbool) -- | & is a reverse application operator. This provides -- notational convenience. Its precedence is one higher than that of the -- forward application operator $, which allows & to be -- nested in $. -- --
-- >>> 5 & (+1) & show -- "6" --(&) :: () => a -> (a -> b) -> b infixl 1 & -- | The constant type functor. -- -- Like Constant, but kind-polymorphic in its second argument and -- with a shorter name. newtype K a (b :: k) :: forall k. () => Type -> k -> Type K :: a -> K a -- | Extract the contents of a K value. unK :: () => K a b -> a instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Schema.PGjsonb instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Schema.PGtsquery instance Squeal.PostgreSQL.Expression.PGSubset ('Squeal.PostgreSQL.Schema.PGvararray ty) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from ty) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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))) 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)) 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)) 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)) instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtext)) instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsvector)) instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsquery)) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null ('Squeal.PostgreSQL.Schema.PGvararray ty))) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGjsonb)) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtext)) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsvector)) instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtext)) instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from (null 'Squeal.PostgreSQL.Schema.PGtsvector)) -- | Type expressions. module Squeal.PostgreSQL.Expression.Type -- | TypeExpressions are used in casts and createTable -- commands. newtype TypeExpression (schemas :: SchemasType) (ty :: NullityType) UnsafeTypeExpression :: ByteString -> TypeExpression [renderTypeExpression] :: TypeExpression -> ByteString -- |
-- >>> printSQL $ true & cast int4 -- (TRUE :: int4) --cast :: TypeExpression schemas ty1 -> Expression outer commons grp schemas params from ty0 -> Expression outer commons grp schemas params from ty1 -- | A safe version of cast which just matches a value with its -- type. -- --
-- >>> printSQL (1 & astype int) -- (1 :: int) --astype :: TypeExpression schemas ty -> Expression outer commons grp schemas params from ty -> Expression outer commons grp schemas params from ty -- | inferredtype will add a type annotation to an Expression -- which can be useful for fixing the storage type of a value. -- --
-- >>> 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 -- | pgtype is a demoted version of a PGType class PGTyped schemas (ty :: NullityType) pgtype :: PGTyped schemas ty => TypeExpression schemas ty -- | The enum or composite type in a Typedef can be expressed by its -- alias. typedef :: (Has sch schemas schema, Has td schema ( 'Typedef ty)) => QualifiedAlias sch td -> TypeExpression schemas (null ty) -- | The composite type corresponding to a Table definition can be -- expressed by its alias. typetable :: (Has sch schemas schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> TypeExpression schemas (null ( 'PGcomposite (TableToRow table))) -- | The composite type corresponding to a View definition can be -- expressed by its alias. typeview :: (Has sch schemas schema, Has vw schema ( 'View view)) => QualifiedAlias sch vw -> TypeExpression schemas (null ( 'PGcomposite view)) -- | logical Boolean (true/false) bool :: TypeExpression schemas (null 'PGbool) -- | signed two-byte integer int2 :: TypeExpression schemas (null 'PGint2) -- | signed two-byte integer smallint :: TypeExpression schemas (null 'PGint2) -- | signed four-byte integer int4 :: TypeExpression schemas (null 'PGint4) -- | signed four-byte integer int :: TypeExpression schemas (null 'PGint4) -- | signed four-byte integer integer :: TypeExpression schemas (null 'PGint4) -- | signed eight-byte integer int8 :: TypeExpression schemas (null 'PGint8) -- | signed eight-byte integer bigint :: TypeExpression schemas (null 'PGint8) -- | arbitrary precision numeric type numeric :: TypeExpression schemas (null 'PGnumeric) -- | single precision floating-point number (4 bytes) float4 :: TypeExpression schemas (null 'PGfloat4) -- | single precision floating-point number (4 bytes) real :: TypeExpression schemas (null 'PGfloat4) -- | double precision floating-point number (8 bytes) float8 :: TypeExpression schemas (null 'PGfloat8) -- | double precision floating-point number (8 bytes) doublePrecision :: TypeExpression schemas (null 'PGfloat8) -- | currency amount money :: TypeExpression schema (null 'PGmoney) -- | variable-length character string text :: TypeExpression schemas (null 'PGtext) -- | fixed-length character string char :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGchar n)) -- | fixed-length character string character :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGchar n)) -- | variable-length character string varchar :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGvarchar n)) -- | variable-length character string characterVarying :: forall n schemas null. (KnownNat n, 1 <= n) => TypeExpression schemas (null ( 'PGvarchar n)) -- | binary data ("byte array") bytea :: TypeExpression schemas (null 'PGbytea) -- | date and time (no time zone) timestamp :: TypeExpression schemas (null 'PGtimestamp) -- | date and time, including time zone timestampWithTimeZone :: TypeExpression schemas (null 'PGtimestamptz) -- | calendar date (year, month, day) date :: TypeExpression schemas (null 'PGdate) -- | time of day (no time zone) time :: TypeExpression schemas (null 'PGtime) -- | time of day, including time zone timeWithTimeZone :: TypeExpression schemas (null 'PGtimetz) -- | time span interval :: TypeExpression schemas (null 'PGinterval) -- | universally unique identifier uuid :: TypeExpression schemas (null 'PGuuid) -- | IPv4 or IPv6 host address inet :: TypeExpression schemas (null 'PGinet) -- | textual JSON data json :: TypeExpression schemas (null 'PGjson) -- | binary JSON data, decomposed jsonb :: TypeExpression schemas (null 'PGjsonb) -- | variable length array vararray :: TypeExpression schemas pg -> TypeExpression schemas (null ( 'PGvararray pg)) -- | fixed length array -- --
-- >>> renderSQL (fixarray @'[2] json) -- "json[2]" --fixarray :: forall dims schemas null pg. All KnownNat dims => TypeExpression schemas pg -> TypeExpression schemas (null ( 'PGfixarray dims pg)) -- | text search query tsvector :: TypeExpression schemas (null 'PGtsvector) -- | text search document tsquery :: TypeExpression schemas (null 'PGtsquery) instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGbool) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGint2) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGint4) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGint8) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGnumeric) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGfloat4) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGfloat8) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGmoney) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtext) instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGchar n)) instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGvarchar n)) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGbytea) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtimestamp) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtimestamptz) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGdate) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtime) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtimetz) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGinterval) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGuuid) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGjson) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGjsonb) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas ty => Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null ('Squeal.PostgreSQL.Schema.PGvararray ty)) 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)) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtsvector) instance Squeal.PostgreSQL.Expression.Type.PGTyped schemas (null 'Squeal.PostgreSQL.Schema.PGtsquery) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Type.TypeExpression schemas ty) -- | Date/Time functions and operators module Squeal.PostgreSQL.Expression.Time -- | Affine space operations on time types. class TimeOp time diff | time -> diff -- |
-- >>> printSQL (makeDate (1984 :* 7 *: 3) !+ 365) -- (make_date(1984, 7, 3) + 365) --(!+) :: TimeOp time diff => Operator (null time) (null diff) (null time) -- |
-- >>> printSQL (365 +! makeDate (1984 :* 7 *: 3)) -- (365 + make_date(1984, 7, 3)) --(+!) :: TimeOp time diff => Operator (null diff) (null time) (null time) -- |
-- >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365) -- (make_date(1984, 7, 3) - 365) --(!-) :: TimeOp time diff => Operator (null time) (null diff) (null time) -- |
-- >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate) -- (make_date(1984, 7, 3) - CURRENT_DATE) --(!-!) :: TimeOp time diff => Operator (null time) (null time) (null diff) infixl 6 !+ infixl 6 +! infixl 6 !- infixl 6 !-! -- |
-- >>> printSQL currentDate -- CURRENT_DATE --currentDate :: Expr (null 'PGdate) -- |
-- >>> printSQL currentTime -- CURRENT_TIME --currentTime :: Expr (null 'PGtimetz) -- |
-- >>> printSQL currentTimestamp -- CURRENT_TIMESTAMP --currentTimestamp :: Expr (null 'PGtimestamptz) -- |
-- >>> printSQL localTime -- LOCALTIME --localTime :: Expr (null 'PGtime) -- |
-- >>> printSQL localTimestamp -- LOCALTIMESTAMP --localTimestamp :: Expr (null 'PGtimestamp) -- | Current date and time (equivalent to currentTimestamp) -- --
-- >>> printSQL now -- now() --now :: Expr (null 'PGtimestamptz) -- | Create date from year, month and day fields -- --
-- >>> printSQL (makeDate (1984 :* 7 *: 3)) -- make_date(1984, 7, 3) --makeDate :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGint4] (null 'PGdate) -- | Create time from hour, minute and seconds fields -- --
-- >>> printSQL (makeTime (8 :* 15 *: 23.5)) -- make_time(8, 15, 23.5) --makeTime :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGfloat8] (null 'PGtime) -- | 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) --makeTimestamp :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] (null 'PGtimestamp) -- | Create timestamp with time zone from year, month, day, hour, minute -- and seconds fields; the current time zone is used -- --
-- >>> printSQL (makeTimestamptz (2013 :* 7 :* 15 :* 8 :* 15 *: 23.5)) -- make_timestamptz(2013, 7, 15, 8, 15, 23.5) --makeTimestamptz :: FunctionN '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] (null 'PGtimestamptz) -- |
-- >>> printSQL $ interval_ 7 Days -- (INTERVAL '7.0 days') --interval_ :: Double -> TimeUnit -> Expr (null 'PGinterval) -- | A TimeUnit to use in interval_ construction. data TimeUnit Years :: TimeUnit Months :: TimeUnit Weeks :: TimeUnit Days :: TimeUnit Hours :: TimeUnit Minutes :: TimeUnit Seconds :: TimeUnit Microseconds :: TimeUnit Milliseconds :: TimeUnit Decades :: TimeUnit Centuries :: TimeUnit Millennia :: TimeUnit instance GHC.Generics.Generic Squeal.PostgreSQL.Expression.Time.TimeUnit instance GHC.Enum.Enum Squeal.PostgreSQL.Expression.Time.TimeUnit instance GHC.Read.Read Squeal.PostgreSQL.Expression.Time.TimeUnit instance GHC.Show.Show Squeal.PostgreSQL.Expression.Time.TimeUnit instance GHC.Classes.Ord Squeal.PostgreSQL.Expression.Time.TimeUnit instance GHC.Classes.Eq Squeal.PostgreSQL.Expression.Time.TimeUnit instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Expression.Time.TimeUnit instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Expression.Time.TimeUnit instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Expression.Time.TimeUnit instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtimestamp 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtimestamptz 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtime 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGtimetz 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGinterval 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Schema.PGdate 'Squeal.PostgreSQL.Schema.PGint4 -- | Text search functions and operators module Squeal.PostgreSQL.Expression.TextSearch -- | tsvector matches tsquery ? (@@) :: Operator (null 'PGtsvector) (null 'PGtsquery) ( 'Null 'PGbool) -- | AND tsquerys together (.&) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery) -- | OR tsquerys together (.|) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery) -- | negate a tsquery (.!) :: null 'PGtsquery :--> null 'PGtsquery -- | tsquery followed by tsquery (<->) :: Operator (null 'PGtsquery) (null 'PGtsquery) (null 'PGtsquery) -- | convert array of lexemes to tsvector arrayToTSvector :: null ( 'PGvararray ( 'NotNull 'PGtext)) :--> null 'PGtsvector -- | number of lexemes in tsvector tsvectorLength :: null 'PGtsvector :--> null 'PGint4 -- | number of lexemes plus operators in tsquery numnode :: null 'PGtsquery :--> null 'PGint4 -- | produce tsquery ignoring punctuation plainToTSquery :: null 'PGtext :--> null 'PGtsquery -- | produce tsquery that searches for a phrase, ignoring -- punctuation phraseToTSquery :: null 'PGtext :--> null 'PGtsquery -- | produce tsquery from a web search style query websearchToTSquery :: null 'PGtext :--> null 'PGtsquery -- | get indexable part of a tsquery queryTree :: null 'PGtsquery :--> null 'PGtext -- | normalize words and convert to tsquery toTSquery :: null 'PGtext :--> null 'PGtsquery -- | reduce document text to tsvector toTSvector :: ty `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => null ty :--> null 'PGtsvector -- | assign weight to each element of tsvector setWeight :: FunctionN '[null 'PGtsvector, null ( 'PGchar 1)] (null 'PGtsvector) -- | remove positions and weights from tsvector strip :: null 'PGtsvector :--> null 'PGtsvector -- | jsonToTSvector (document *: filter) reduce each value in the -- document, specified by filter to a tsvector, and then -- concatenate those in document order to produce a single -- tsvector. filter is a json array, that enumerates what -- kind of elements need to be included into the resulting -- tsvector. Possible values for filter are "string" (to include -- all string values), "numeric" (to include all numeric values in the -- string format), "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) -- | jsonbToTSvector (document *: filter) reduce each value in the -- document, specified by filter to a tsvector, and then -- concatenate those in document order to produce a single -- tsvector. filter is a jsonb array, that enumerates what -- kind of elements need to be included into the resulting -- tsvector. Possible values for filter are "string" (to include -- all string values), "numeric" (to include all numeric values in the -- string format), "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) -- | remove given lexeme from tsvector tsDelete :: FunctionN '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull 'PGtext))] (null 'PGtsvector) -- | select only elements with given weights from tsvector tsFilter :: FunctionN '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull ( 'PGchar 1)))] (null 'PGtsvector) -- | display a tsquery match tsHeadline :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => FunctionN '[null document, null 'PGtsquery] (null 'PGtext) -- | String functions and operators module Squeal.PostgreSQL.Expression.Text -- |
-- >>> printSQL $ lower "ARRRGGG" -- lower(E'ARRRGGG') --lower :: null 'PGtext :--> null 'PGtext -- |
-- >>> printSQL $ upper "eeee" -- upper(E'eeee') --upper :: null 'PGtext :--> null 'PGtext -- |
-- >>> printSQL $ charLength "four" -- char_length(E'four') --charLength :: null 'PGtext :--> null 'PGint4 -- | The like expression returns true if the string matches -- the supplied pattern. If pattern does not contain -- percent signs or underscores, then the pattern only represents the -- string itself; in that case like acts like the equals operator. -- An underscore (_) in pattern stands for (matches) any single -- character; a percent sign (%) matches any sequence of zero or more -- characters. -- --
-- >>> printSQL $ "abc" `like` "a%" -- (E'abc' LIKE E'a%') --like :: Operator (null 'PGtext) (null 'PGtext) ( 'Null 'PGbool) -- | The key word ILIKE can be used instead of LIKE to make the match -- case-insensitive according to the active locale. -- --
-- >>> printSQL $ "abc" `ilike` "a%" -- (E'abc' ILIKE E'a%') --ilike :: Operator (null 'PGtext) (null 'PGtext) ( 'Null 'PGbool) -- | Sort expressions module Squeal.PostgreSQL.Expression.Sort -- | SortExpressions are used by orderBy to optionally sort -- the results of a Query. Asc or Desc set the sort -- direction of a NotNull result column to ascending or -- descending. Ascending order puts smaller values first, where "smaller" -- is defined in terms of the .< operator. Similarly, -- descending order is determined with the .> operator. -- AscNullsFirst, 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 [Asc] :: Expression outer commons grp schemas params from ( 'NotNull ty) -> SortExpression outer commons grp schemas params from [Desc] :: Expression outer commons grp schemas params from ( 'NotNull ty) -> SortExpression outer commons grp schemas params from [AscNullsFirst] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from [AscNullsLast] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from [DescNullsFirst] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from [DescNullsLast] :: Expression outer commons grp schemas params from ( 'Null ty) -> SortExpression outer commons grp schemas params from -- | The orderBy clause causes the result rows of a -- TableExpression to be sorted according to the specified -- SortExpression(s). If two rows are equal according to the -- leftmost expression, they are compared according to the next -- expression and so on. If they are equal according to all specified -- expressions, they are returned in an implementation-dependent order. -- -- You can also control the order in which rows are processed by window -- functions using orderBy within Over. class OrderBy expr orderBy :: OrderBy expr => [SortExpression outer commons grp schemas params from] -> expr outer commons grp schemas params from -> expr outer commons grp schemas params from instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Sort.SortExpression outer commons grp schemas params from) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Sort.SortExpression outer commons grp schemas params from) -- | Parameters, out-of-line data values module Squeal.PostgreSQL.Expression.Parameter -- | A HasParameter constraint is used to indicate a value that is -- supplied externally to a SQL statement. manipulateParams, -- queryParams and traversePrepared support specifying data -- values separately from the SQL command string, in which case -- params are used to refer to the out-of-line data values. class KnownNat n => HasParameter (n :: Nat) (params :: [NullityType]) (ty :: NullityType) | n params -> ty -- | parameter takes a Nat using type application and a -- TypeExpression. -- --
-- >>> let expr = parameter @1 int4 :: Expression outer '[] grp schemas '[ 'Null 'PGint4] from ('Null 'PGint4)
--
-- >>> printSQL expr
-- ($1 :: int4)
--
parameter :: HasParameter n params ty => TypeExpression schemas ty -> Expression outer commons grp schemas params from ty
-- | 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)
--
-- >>> 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
instance Squeal.PostgreSQL.Expression.Parameter.HasParameter 1 (ty1 : tys) ty1
instance (GHC.TypeNats.KnownNat n, Squeal.PostgreSQL.Expression.Parameter.HasParameter (n GHC.TypeNats.- 1) params ty) => Squeal.PostgreSQL.Expression.Parameter.HasParameter n (ty' : params) ty
-- | Mathematical functions and operators
module Squeal.PostgreSQL.Expression.Math
-- |
-- >>> :{
-- let
-- expression :: Expr (null 'PGfloat4)
-- expression = atan2_ (pi *: 2)
-- in printSQL expression
-- :}
-- atan2(pi(), 2)
--
atan2_ :: float `In` PGFloating => FunctionN '[null float, null float] (null float)
-- | integer division, truncates the result
--
--
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
-- expression = 5 `quot_` 2
-- in printSQL expression
-- :}
-- (5 / 2)
--
quot_ :: int `In` PGIntegral => Operator (null int) (null int) (null int)
-- | remainder upon integer division
--
--
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
-- expression = 5 `rem_` 2
-- in printSQL expression
-- :}
-- (5 % 2)
--
rem_ :: int `In` PGIntegral => Operator (null int) (null int) (null int)
-- |
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)
-- expression = trunc pi
-- in printSQL expression
-- :}
-- trunc(pi())
--
trunc :: frac `In` PGFloating => null frac :--> null frac
-- |
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)
-- expression = round_ pi
-- in printSQL expression
-- :}
-- round(pi())
--
round_ :: frac `In` PGFloating => null frac :--> null frac
-- |
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas params from (null 'PGfloat4)
-- expression = ceiling_ pi
-- in printSQL expression
-- :}
-- ceiling(pi())
--
ceiling_ :: frac `In` PGFloating => null frac :--> null frac
-- | Logical expressions and operators
module Squeal.PostgreSQL.Expression.Logic
-- | A Condition is an Expression, which can evaluate to
-- true, false or 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)
-- | -- >>> printSQL true -- TRUE --true :: Expr (null 'PGbool) -- |
-- >>> printSQL false -- FALSE --false :: Expr (null 'PGbool) -- |
-- >>> printSQL $ not_ true -- (NOT TRUE) --not_ :: null 'PGbool :--> null 'PGbool -- |
-- >>> printSQL $ true .&& false -- (TRUE AND FALSE) --(.&&) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool) infixr 3 .&& -- |
-- >>> printSQL $ true .|| false -- (TRUE OR FALSE) --(.||) :: Operator (null 'PGbool) (null 'PGbool) (null 'PGbool) infixr 2 .|| -- |
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas 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
--
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
-- |
-- >>> :{
-- let
-- expression :: Expression outer commons grp schemas params from (null 'PGint2)
-- expression = ifThenElse true 1 0
-- in printSQL expression
-- :}
-- CASE WHEN TRUE THEN 1 ELSE 0 END
--
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
-- | Null values and null handling functions
module Squeal.PostgreSQL.Expression.Null
-- | analagous to Nothing
--
-- -- >>> printSQL null_ -- NULL --null_ :: Expr ( 'Null ty) -- | analagous to Just -- --
-- >>> printSQL $ notNull true -- TRUE --notNull :: 'NotNull ty :--> 'Null ty -- | 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) -- | analagous to fromMaybe using COALESCE -- --
-- >>> printSQL $ fromNull true null_ -- COALESCE(NULL, TRUE) --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) -- |
-- >>> printSQL $ null_ & isNull -- NULL IS NULL --isNull :: 'Null ty :--> null 'PGbool -- |
-- >>> printSQL $ null_ & isNotNull -- NULL IS NOT NULL --isNotNull :: 'Null ty :--> null 'PGbool -- | analagous to maybe using IS NULL -- --
-- >>> 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 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 -- | right inverse to fromNull, if its arguments are equal then -- nullIf gives NULL. -- --
-- >>> :set -XTypeApplications -XDataKinds
--
-- >>> let expr = nullIf (false *: param @1) :: Expression outer commons grp schemas '[ 'NotNull 'PGbool] from ('Null 'PGbool)
--
-- >>> printSQL expr
-- NULLIF(FALSE, ($1 :: bool))
--
nullIf :: FunctionN '[ 'NotNull ty, 'NotNull ty] ( 'Null ty)
-- | Comparison functions and operators
module Squeal.PostgreSQL.Expression.Comparison
-- | Comparison operations like .==, ./=, .>,
-- .>=, .< and .<= will produce
-- NULLs if one of their arguments is NULL.
--
-- -- >>> printSQL $ true .== null_ -- (TRUE = NULL) --(.==) :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) infix 4 .== -- |
-- >>> printSQL $ true ./= null_ -- (TRUE <> NULL) --(./=) :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) infix 4 ./= -- |
-- >>> printSQL $ true .>= null_ -- (TRUE >= NULL) --(.>=) :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) infix 4 .>= -- |
-- >>> printSQL $ true .< null_ -- (TRUE < NULL) --(.<) :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) infix 4 .< -- |
-- >>> printSQL $ true .<= null_ -- (TRUE <= NULL) --(.<=) :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) infix 4 .<= -- |
-- >>> printSQL $ true .> null_ -- (TRUE > NULL) --(.>) :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) infix 4 .> -- |
-- >>> let expr = greatest [param @1] currentTimestamp :: Expression outer commons grp schemas '[ 'NotNull 'PGtimestamptz] from ('NotNull 'PGtimestamptz)
--
-- >>> printSQL expr
-- GREATEST(($1 :: timestamp with time zone), CURRENT_TIMESTAMP)
--
greatest :: FunctionVar ty ty ty
-- | -- >>> printSQL $ least [null_] currentTimestamp -- LEAST(NULL, CURRENT_TIMESTAMP) --least :: FunctionVar ty ty ty -- | 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 -- |
-- >>> printSQL $ true `between` (null_, false) -- TRUE BETWEEN NULL AND FALSE --between :: BetweenExpr -- |
-- >>> printSQL $ true `notBetween` (null_, false) -- TRUE NOT BETWEEN NULL AND FALSE --notBetween :: BetweenExpr -- | between, after sorting the comparison values -- --
-- >>> printSQL $ true `betweenSymmetric` (null_, false) -- TRUE BETWEEN SYMMETRIC NULL AND FALSE --betweenSymmetric :: BetweenExpr -- | not between, after sorting the comparison values -- --
-- >>> printSQL $ true `notBetweenSymmetric` (null_, false) -- TRUE NOT BETWEEN SYMMETRIC NULL AND FALSE --notBetweenSymmetric :: BetweenExpr -- | not equal, treating null like an ordinary value -- --
-- >>> printSQL $ true `isDistinctFrom` null_ -- (TRUE IS DISTINCT FROM NULL) --isDistinctFrom :: Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) -- | equal, treating null like an ordinary value -- --
-- >>> printSQL $ true `isNotDistinctFrom` null_ -- (TRUE IS NOT DISTINCT FROM NULL) --isNotDistinctFrom :: Operator (null0 ty) (null1 ty) ( 'NotNull 'PGbool) -- | is true -- --
-- >>> printSQL $ true & isTrue -- (TRUE IS TRUE) --isTrue :: null0 'PGbool :--> null1 'PGbool -- | is false or unknown -- --
-- >>> printSQL $ true & isNotTrue -- (TRUE IS NOT TRUE) --isNotTrue :: null0 'PGbool :--> null1 'PGbool -- | is false -- --
-- >>> printSQL $ true & isFalse -- (TRUE IS FALSE) --isFalse :: null0 'PGbool :--> null1 'PGbool -- | is true or unknown -- --
-- >>> printSQL $ true & isNotFalse -- (TRUE IS NOT FALSE) --isNotFalse :: null0 'PGbool :--> null1 'PGbool -- | is unknown -- --
-- >>> printSQL $ true & isUnknown -- (TRUE IS UNKNOWN) --isUnknown :: null0 'PGbool :--> null1 'PGbool -- | is true or false -- --
-- >>> printSQL $ true & isNotUnknown -- (TRUE IS NOT UNKNOWN) --isNotUnknown :: null0 'PGbool :--> null1 'PGbool -- | Aggregate functions module Squeal.PostgreSQL.Expression.Aggregate -- | Aggregate functions compute a single result from a set of input -- values. Aggregate functions can be used as GroupedBy -- Expressions as well as WindowFunctions. class Aggregate expr1 exprN aggr | aggr -> expr1, aggr -> exprN -- | A special aggregation that does not require an input -- --
-- >>> :{
-- let
-- expression :: Expression '[] commons ('Grouped bys) schemas params from ('NotNull 'PGint8)
-- expression = countStar
-- in printSQL expression
-- :}
-- count(*)
--
countStar :: Aggregate expr1 exprN aggr => aggr ( 'NotNull 'PGint8)
-- |
-- >>> :{
-- let
-- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
-- expression = count (All #col)
-- in printSQL expression
-- :}
-- count(ALL "col")
--
count :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'NotNull 'PGint8)
-- |
-- >>> :{
-- let
-- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)
-- expression = sum_ (Distinct #col)
-- in printSQL expression
-- :}
-- sum(DISTINCT "col")
--
sum_ :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGSum ty))
-- | input values, including nulls, concatenated into an array
arrayAgg :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'Null ( 'PGvararray ty))
-- | aggregates values as a JSON array
jsonAgg :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( 'Null 'PGjson)
-- | aggregates values as a JSON array
jsonbAgg :: Aggregate expr1 exprN aggr => expr1 ty -> aggr ( '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 = bitAnd (Distinct #col)
-- in printSQL expression
-- :}
-- bit_and(DISTINCT "col")
--
bitAnd :: (Aggregate expr1 exprN aggr, int `In` PGIntegral) => expr1 (null int) -> aggr ( '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 = bitOr (All #col)
-- in printSQL expression
-- :}
-- bit_or(ALL "col")
--
bitOr :: (Aggregate expr1 exprN aggr, int `In` PGIntegral) => expr1 (null int) -> aggr ( '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
-- in printSQL winFun
-- :}
-- bool_and("col")
--
boolAnd :: Aggregate expr1 exprN aggr => expr1 (null 'PGbool) -> aggr ( '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 = boolOr (All #col)
-- in printSQL expression
-- :}
-- bool_or(ALL "col")
--
boolOr :: Aggregate expr1 exprN aggr => expr1 (null 'PGbool) -> aggr ( 'Null 'PGbool)
-- | equivalent to boolAnd
--
--
-- >>> :{
-- let
-- expression :: Expression '[] commons ('Grouped bys) schemas params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
-- expression = every (Distinct #col)
-- in printSQL expression
-- :}
-- every(DISTINCT "col")
--
every :: Aggregate expr1 exprN aggr => expr1 (null 'PGbool) -> aggr ( 'Null 'PGbool)
-- | maximum value of expression across all input values
max_ :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null ty)
-- | minimum value of expression across all input values
min_ :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null ty)
-- | the average (arithmetic mean) of all input values
avg :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( '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))
-- in printSQL expression
-- :}
-- corr(ALL "y", "x")
--
corr :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( '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))
-- in printSQL expression
-- :}
-- covar_pop(ALL "y", "x")
--
covarPop :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | sample covariance
--
--
-- >>> :{
-- let
-- winFun :: WindowFunction '[] c 'Ungrouped s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- winFun = covarSamp (#y *: #x)
-- in printSQL winFun
-- :}
-- covar_samp("y", "x")
--
covarSamp :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( '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))
-- in printSQL expression
-- :}
-- regr_avgx(ALL "y", "x")
--
regrAvgX :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( '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)
-- in printSQL winFun
-- :}
-- regr_avgy("y", "x")
--
regrAvgY :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( '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)
-- in printSQL winFun
-- :}
-- regr_count("y", "x")
--
regrCount :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( '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
-- (x)) in printSQL expression :} regr_intercept(ALL "y", "x")
regrIntercept :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | regr_r2(Y, X), square of the correlation coefficient
regrR2 :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | regr_slope(Y, X), slope of the least-squares-fit linear
-- equation determined by the (X, Y) pairs
regrSlope :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | regr_sxx(Y, X), sum(X^2) - sum(X)^2/N (“sum of squares” of
-- the independent variable)
regrSxx :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | regr_sxy(Y, X), sum(X*Y) - sum(X) * sum(Y)/N (“sum of
-- products” of independent times dependent variable)
regrSxy :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | regr_syy(Y, X), sum(Y^2) - sum(Y)^2/N (“sum of squares” of
-- the dependent variable)
regrSyy :: Aggregate expr1 exprN aggr => exprN '[null 'PGfloat8, null 'PGfloat8] -> aggr ( 'Null 'PGfloat8)
-- | historical alias for stddevSamp
stddev :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
-- | population standard deviation of the input values
stddevPop :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
-- | sample standard deviation of the input values
stddevSamp :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
-- | historical alias for varSamp
variance :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
-- | population variance of the input values (square of the population
-- standard deviation)
varPop :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
-- | sample variance of the input values (square of the sample standard
-- deviation)
varSamp :: Aggregate expr1 exprN aggr => expr1 (null ty) -> aggr ( 'Null (PGAvg ty))
-- | Distinctions are used for the input of Aggregate
-- Expressions. 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
data Distinction (expr :: kind -> Type) (ty :: kind)
All :: expr ty -> Distinction
Distinct :: expr ty -> Distinction
-- | A type family that calculates PGSumPGType of a given
-- argument PGType.
type family PGSum ty
-- | A type family that calculates PGAvg type of a PGType.
type family PGAvg ty
instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Classes.Ord (expr ty) => GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Classes.Eq (expr ty) => GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Show.Show (expr ty) => GHC.Show.Show (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
instance forall kind (expr :: kind -> *) (ty :: kind). GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Aggregate.Distinction expr ty)
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)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from) ty)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Aggregate.Distinction (Squeal.PostgreSQL.Expression.Expression outer commons grp schemas params from) ty)
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)
-- | Window functions and definitions
module Squeal.PostgreSQL.Expression.Window
-- | The partitionBy clause within Over divides the rows into
-- groups, or partitions, that share the same values of the
-- partitionBy Expression(s). For each row, the window
-- function is computed across the rows that fall into the same partition
-- as the current row.
partitionBy :: SListI bys => NP (Expression outer commons grp schemas params from) bys -> WindowDefinition outer commons grp schemas params from
-- | rank of the current row with gaps; same as rowNumber of its
-- first peer
--
-- -- >>> printSQL rank -- rank() --rank :: WinFun0 ( 'NotNull 'PGint8) -- | number of the current row within its partition, counting from 1 -- --
-- >>> printSQL rowNumber -- row_number() --rowNumber :: WinFun0 ( 'NotNull 'PGint8) -- | rank of the current row without gaps; this function counts peer groups -- --
-- >>> printSQL denseRank -- dense_rank() --denseRank :: WinFun0 ( 'NotNull 'PGint8) -- | relative rank of the current row: (rank - 1) / (total partition rows - -- 1) -- --
-- >>> printSQL percentRank -- percent_rank() --percentRank :: WinFun0 ( 'NotNull 'PGfloat8) -- | cumulative distribution: (number of partition rows preceding or peer -- with current row) / total partition rows -- --
-- >>> printSQL cumeDist -- cume_dist() --cumeDist :: WinFun0 ( 'NotNull 'PGfloat8) -- | integer ranging from 1 to the argument value, dividing the partition -- as equally as possible -- --
-- >>> printSQL $ ntile 5 -- ntile(5) --ntile :: WinFun1 ( 'NotNull 'PGint4) ( 'NotNull 'PGint4) -- | returns value evaluated at the row that is offset rows before the -- current row within the partition; if there is no such row, instead -- return default (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 -- | returns value evaluated at the row that is offset rows after the -- current row within the partition; if there is no such row, instead -- return default (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 -- | returns value evaluated at the row that is the first row of the window -- frame firstValue :: WinFun1 ty ty -- | returns value evaluated at the row that is the last row of the window -- frame lastValue :: WinFun1 ty ty -- | 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) -- | escape hatch for defining window functions unsafeWindowFunction1 :: ByteString -> WinFun1 x y -- | escape hatch for defining multi-argument window functions unsafeWindowFunctionN :: SListI xs => ByteString -> WinFunN xs y -- | A window function performs a calculation across a set of table rows -- that are somehow related to the current row. This is comparable to the -- type of calculation that can be done with an aggregate function. -- However, window functions do not cause rows to become grouped into a -- single output row like non-window aggregate calls would. Instead, the -- rows retain their separate identities. Behind the scenes, the window -- function is able to access more than just the current row of the query -- result. newtype WindowFunction (outer :: FromType) (commons :: FromType) (grp :: Grouping) (schemas :: SchemasType) (params :: [NullityType]) (from :: FromType) (ty :: NullityType) UnsafeWindowFunction :: ByteString -> WindowFunction [renderWindowFunction] :: WindowFunction -> ByteString -- | A WindowDefinition is a set of table rows that are somehow -- related to the current row data WindowDefinition outer commons grp schemas params from [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 -- | 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 " 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 " input" -> WindowFunction outer commons grp schemas 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 " inputs" -> WindowFunction outer commons grp schemas params from y " output" instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty) 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) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowFunction outer commons grp schemas params from ty) instance Squeal.PostgreSQL.Expression.Sort.OrderBy Squeal.PostgreSQL.Expression.Window.WindowDefinition instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowDefinition outer commons schemas from grp params) -- | Squeal queries. module Squeal.PostgreSQL.Query -- | The top level Query_ type is parameterized by a -- schemas SchemasType, against which the query is -- type-checked, an input parameters Haskell Type, and an -- ouput row Haskell Type. -- -- A top-level query can be run using runQueryParams, or if -- parameters = () using runQuery. -- -- Generally, parameters will be a Haskell tuple or record whose -- entries may be referenced using positional parameters and -- row will be a Haskell record, whose entries will be targeted -- using overloaded labels. -- -- Let's see some examples of queries. -- --
-- >>> :set -XDeriveAnyClass -XDerivingStrategies
--
-- >>> :{
-- data Row a b = Row { col1 :: a, col2 :: b }
-- deriving stock (GHC.Generic)
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- :}
--
--
-- simple query:
--
--
-- >>> type Columns = '["col1" ::: 'NoDef :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]
--
-- >>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = select Star (from (table #tab))
-- in printSQL query
-- :}
-- SELECT * FROM "tab" AS "tab"
--
--
-- restricted query:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query =
-- select_ ((#col1 + #col2) `as` #col1 :* #col1 `as` #col2)
-- ( from (table #tab)
-- & where_ (#col1 .> #col2)
-- & where_ (#col2 .> 0) )
-- in printSQL query
-- :}
-- SELECT ("col1" + "col2") AS "col1", "col1" AS "col2" FROM "tab" AS "tab" WHERE (("col1" > "col2") AND ("col2" > 0))
--
--
-- subquery:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = select Star (from (subquery (select Star (from (table #tab)) `as` #sub)))
-- in printSQL query
-- :}
-- SELECT * FROM (SELECT * FROM "tab" AS "tab") AS "sub"
--
--
-- limits and offsets:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = select Star (from (table #tab) & limit 100 & offset 2 & limit 50 & offset 2)
-- in printSQL query
-- :}
-- SELECT * FROM "tab" AS "tab" LIMIT 50 OFFSET 4
--
--
-- parameterized query:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) (Only Int32) (Row Int32 Int32)
-- query = select Star (from (table #tab) & where_ (#col1 .> param @1))
-- in printSQL query
-- :}
-- SELECT * FROM "tab" AS "tab" WHERE ("col1" > ($1 :: int4))
--
--
-- aggregation query:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int64 Int32)
-- query =
-- select_ ((fromNull 0 (sum_ (All #col2))) `as` #col1 :* #col1 `as` #col2)
-- ( from (table (#tab `as` #table1))
-- & groupBy #col1
-- & 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)
--
--
-- sorted query:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = select Star (from (table #tab) & orderBy [#col1 & Asc])
-- in printSQL query
-- :}
-- SELECT * FROM "tab" AS "tab" ORDER BY "col1" ASC
--
--
-- joins:
--
--
-- >>> :{
-- type OrdersColumns =
-- '[ "id" ::: 'NoDef :=> 'NotNull 'PGint4
-- , "price" ::: 'NoDef :=> 'NotNull 'PGfloat4
-- , "customer_id" ::: 'NoDef :=> 'NotNull 'PGint4
-- , "shipper_id" ::: 'NoDef :=> 'NotNull 'PGint4 ]
-- :}
--
--
--
-- >>> :{
-- type OrdersConstraints =
-- '["pk_orders" ::: PrimaryKey '["id"]
-- ,"fk_customers" ::: ForeignKey '["customer_id"] "customers" '["id"]
-- ,"fk_shippers" ::: ForeignKey '["shipper_id"] "shippers" '["id"] ]
-- :}
--
--
--
-- >>> type NamesColumns = '["id" ::: 'NoDef :=> 'NotNull 'PGint4, "name" ::: 'NoDef :=> 'NotNull 'PGtext]
--
-- >>> type CustomersConstraints = '["pk_customers" ::: PrimaryKey '["id"]]
--
-- >>> type ShippersConstraints = '["pk_shippers" ::: PrimaryKey '["id"]]
--
-- >>> :{
-- type OrdersSchema =
-- '[ "orders" ::: 'Table (OrdersConstraints :=> OrdersColumns)
-- , "customers" ::: 'Table (CustomersConstraints :=> NamesColumns)
-- , "shippers" ::: 'Table (ShippersConstraints :=> NamesColumns) ]
-- :}
--
--
--
-- >>> :{
-- data Order = Order
-- { price :: Float
-- , customerName :: Text
-- , shipperName :: Text
-- } deriving GHC.Generic
-- instance SOP.Generic Order
-- instance SOP.HasDatatypeInfo Order
-- :}
--
--
--
-- >>> :{
-- 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)
-- & innerJoin (table (#customers `as` #c))
-- (#o ! #customer_id .== #c ! #id)
-- & innerJoin (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 "customers" AS "c" ON ("o"."customer_id" = "c"."id") INNER JOIN "shippers" AS "s" ON ("o"."shipper_id" = "s"."id")
--
--
-- self-join:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = select
-- (#t1 & DotStar)
-- (from (table (#tab `as` #t1) & crossJoin (table (#tab `as` #t2))))
-- in printSQL query
-- :}
-- SELECT "t1".* FROM "tab" AS "t1" CROSS JOIN "tab" AS "t2"
--
--
-- value queries:
--
--
-- >>> :{
-- let
-- query :: Query_ schemas () (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")
--
--
-- set operations:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = select Star (from (table #tab)) `unionAll` select Star (from (table #tab))
-- in printSQL query
-- :}
-- (SELECT * FROM "tab" AS "tab") UNION ALL (SELECT * FROM "tab" AS "tab")
--
--
-- with queries:
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int32)
-- query = with (
-- select Star (from (table #tab)) `as` #cte1 :>>
-- select Star (from (common #cte1)) `as` #cte2
-- ) (select Star (from (common #cte2)))
-- in printSQL query
-- :}
-- WITH "cte1" AS (SELECT * FROM "tab" AS "tab"), "cte2" AS (SELECT * FROM "cte1" AS "cte1") SELECT * FROM "cte2" AS "cte2"
--
--
-- window function queries
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Row Int32 Int64)
-- query = select
-- (#col1 & Also (rank `as` #col2 `Over` (partitionBy #col1 & orderBy [#col2 & Asc])))
-- (from (table #tab))
-- in printSQL query
-- :}
-- SELECT "col1" AS "col1", rank() OVER (PARTITION BY "col1" ORDER BY "col2" ASC) AS "col2" FROM "tab" AS "tab"
--
--
-- correlated subqueries
--
--
-- >>> :{
-- let
-- query :: Query_ (Public Schema) () (Only Int32)
-- query =
-- select (#col1 `as` #fromOnly) (from (table (#tab `as` #t1))
-- & where_ (exists (
-- select Star (from (table (#tab `as` #t2))
-- & where_ (#t2 ! #col2 .== #t1 ! #col1)))))
-- in printSQL query
-- :}
-- SELECT "col1" AS "fromOnly" FROM "tab" AS "t1" WHERE EXISTS (SELECT * FROM "tab" AS "t2" WHERE ("t2"."col2" = "t1"."col1"))
--
type family Query_ (schemas :: SchemasType) (parameters :: Type) (row :: Type)
-- | The process of retrieving or the command to retrieve data from a
-- database is called a Query.
--
-- The general Query type is parameterized by
--
--
-- >>> 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] -> Query outer commons schemas params cols
-- | 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 -> Query outer commons schemas params cols
-- | 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
-- | 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
-- | 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
-- | 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
-- | 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
-- | 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
-- | with provides a way to write auxiliary statements for use in a
-- larger query. These statements, referred to as
-- CommonTableExpressions, can be thought of as defining temporary
-- tables that exist just for one query.
class With statement
with :: With statement => AlignedList (CommonTableExpression statement schemas params) commons0 commons1 -> statement commons1 schemas params row -> statement commons0 schemas params row
-- | A CommonTableExpression is an auxiliary statement in a
-- with clause.
data CommonTableExpression statement (schemas :: SchemasType) (params :: [NullityType]) (commons0 :: FromType) (commons1 :: FromType)
[CommonTableExpression] :: Aliased (statement commons schemas params) (cte ::: common) -> CommonTableExpression statement schemas params commons ((cte ::: common) : commons)
-- |
-- >>> 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
-- | A TableExpression computes a table. The table expression
-- contains a fromClause that is optionally followed by a
-- whereClause, groupByClause, havingClause,
-- orderByClause, limitClause and offsetClauses.
-- 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 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
-- | 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.
[fromClause] :: TableExpression -> FromClause outer commons 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.
[whereClause] :: TableExpression -> [Condition outer commons 'Ungrouped schemas params 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.
[groupByClause] :: TableExpression -> GroupByClause grp 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).
[havingClause] :: TableExpression -> HavingClause 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.
[orderByClause] :: TableExpression -> [SortExpression outer commons grp schemas params from]
-- | 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).
[limitClause] :: TableExpression -> [Word64]
-- | The offsetClause is combined with + 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.
[offsetClause] :: TableExpression -> [Word64]
-- | 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 -> TableExpression outer commons 'Ungrouped schemas params from
-- | A where_ is an endomorphism of TableExpressions which
-- adds a search condition to the whereClause.
where_ :: Condition outer commons 'Ungrouped schemas params from -> TableExpression outer commons grp schemas params from -> TableExpression outer commons grp schemas params from
-- | A groupBy is a transformation of TableExpressions 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 -> TableExpression outer commons 'Ungrouped schemas params from -> TableExpression outer commons ( 'Grouped bys) schemas params from
-- | A having is an endomorphism of TableExpressions which
-- adds a search condition to the havingClause.
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
-- | A limit is an endomorphism of TableExpressions which
-- adds to the limitClause.
limit :: Word64 -> TableExpression outer commons grp schemas params from -> TableExpression outer commons grp schemas params from
-- | An offset is an endomorphism of TableExpressions which
-- adds to the offsetClause.
offset :: Word64 -> TableExpression outer commons grp schemas params from -> TableExpression outer commons grp schemas params from
-- | 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 :: ByteString -> FromClause outer commons schemas params from
[renderFromClause] :: FromClause outer commons schemas params from -> ByteString
-- | 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]
-- | subquery derives a table from a Query.
subquery :: Aliased (Query outer commons schemas params) query -> FromClause outer commons schemas params '[query]
-- | 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]
-- | 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]
-- | 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 -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join left right)
-- | left & innerJoin right on. The joined table is filtered
-- by the on condition.
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)
-- | 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 -> Condition outer commons 'Ungrouped schemas params (Join left right) -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join left (NullifyFrom right))
-- | 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 -> Condition outer commons 'Ungrouped schemas params (Join left right) -> FromClause outer commons schemas params left -> FromClause outer commons schemas params (Join (NullifyFrom left) right)
-- | 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 -> 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))
-- | Bys 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))
[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)
-- | 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 Expressions must be
-- aggregated in Group Nil. In general, all output
-- Expressions in the complement of bys must be
-- aggregated in Group bys.
data GroupByClause grp from
[NoGroups] :: GroupByClause 'Ungrouped from
[Group] :: SListI bys => NP (By from) bys -> GroupByClause ( 'Grouped bys) from
-- | 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
[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
instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.TableExpression outer commons grp schemas params from)
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)
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)
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)
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)
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)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
instance GHC.Show.Show (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
instance GHC.Show.Show (Squeal.PostgreSQL.Query.By from by)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.By from by)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.By from by)
instance GHC.Show.Show (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
instance Squeal.PostgreSQL.Query.With (Squeal.PostgreSQL.Query.Query outer)
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)
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)
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)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.TableExpression outer commons grp schemas params from)
instance Squeal.PostgreSQL.Expression.Sort.OrderBy Squeal.PostgreSQL.Query.TableExpression
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.HavingClause outer commons grp schemas params from)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.GroupByClause grp from)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.By from by)
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)
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)
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)
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)
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)
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)
instance Squeal.PostgreSQL.List.Additional (Squeal.PostgreSQL.Query.Selection outer commons grp schemas params from)
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)
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)
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)
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)
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)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Selection outer commons grp schemas params from row)
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])
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Query outer commons schemas params row)
-- | Squeal data manipulation language.
module Squeal.PostgreSQL.Manipulation
-- | The top level Manipulation_ type is parameterized by a
-- schemas SchemasType, against which the query is
-- type-checked, an input parameters Haskell Type, and an
-- ouput row Haskell Type.
--
-- A top-level Manipulation_ can be run using
-- manipulateParams, or if parameters = () using
-- manipulate.
--
-- Generally, parameters will be a Haskell tuple or record whose
-- entries may be referenced using positional parameters and
-- row will be a Haskell record, whose entries will be targeted
-- using overloaded labels.
--
--
-- >>> :set -XDeriveAnyClass -XDerivingStrategies
--
-- >>> :{
-- data Row a b = Row { col1 :: a, col2 :: b }
-- deriving stock (GHC.Generic)
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- :}
--
--
-- simple insert:
--
--
-- >>> type Columns = '["col1" ::: 'NoDef :=> 'Null 'PGint4, "col2" ::: 'Def :=> 'NotNull 'PGint4]
--
-- >>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) () ()
-- manipulation =
-- insertInto_ #tab (Values_ (Set 2 `as` #col1 :* Default `as` #col2))
-- in printSQL manipulation
-- :}
-- INSERT INTO "tab" ("col1", "col2") VALUES (2, DEFAULT)
--
--
-- parameterized insert:
--
--
-- >>> type Columns = '["col1" ::: 'NoDef :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]
--
-- >>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) (Int32, Int32) ()
-- manipulation =
-- insertInto_ #tab (Values_ (Set (param @1) `as` #col1 :* Set (param @2) `as` #col2))
-- in printSQL manipulation
-- :}
-- INSERT INTO "tab" ("col1", "col2") VALUES (($1 :: int4), ($2 :: int4))
--
--
-- returning insert:
--
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) () (Only Int32)
-- manipulation =
-- insertInto #tab (Values_ (Set 2 `as` #col1 :* Set 3 `as` #col2))
-- OnConflictDoRaise (Returning (#col1 `as` #fromOnly))
-- in printSQL manipulation
-- :}
-- INSERT INTO "tab" ("col1", "col2") VALUES (2, 3) RETURNING "col1" AS "fromOnly"
--
--
-- upsert:
--
--
-- >>> type CustomersColumns = '["name" ::: 'NoDef :=> 'NotNull 'PGtext, "email" ::: 'NoDef :=> 'NotNull 'PGtext]
--
-- >>> type CustomersConstraints = '["uq" ::: 'Unique '["name"]]
--
-- >>> type CustomersSchema = '["customers" ::: 'Table (CustomersConstraints :=> CustomersColumns)]
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public CustomersSchema) () ()
-- manipulation =
-- insertInto #customers
-- (Values_ (Set "John Smith" `as` #name :* Set "john@smith.com" `as` #email))
-- (OnConflict (OnConstraint #uq)
-- (DoUpdate (Set (#excluded ! #email <> "; " <> #customers ! #email) `as` #email) []))
-- (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"))
--
--
-- query insert:
--
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) () ()
-- manipulation = insertInto_ #tab (Subquery (select Star (from (table #tab))))
-- in printSQL manipulation
-- :}
-- INSERT INTO "tab" SELECT * FROM "tab" AS "tab"
--
--
-- update:
--
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) () ()
-- manipulation = update_ #tab (Set 2 `as` #col1) (#col1 ./= #col2)
-- in printSQL manipulation
-- :}
-- UPDATE "tab" SET "col1" = 2 WHERE ("col1" <> "col2")
--
--
-- delete:
--
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) () (Row Int32 Int32)
-- manipulation = deleteFrom #tab NoUsing (#col1 .== #col2) (Returning Star)
-- in printSQL manipulation
-- :}
-- DELETE FROM "tab" WHERE ("col1" = "col2") RETURNING *
--
--
-- delete and using clause:
--
--
-- >>> :{
-- type Schema3 =
-- '[ "tab" ::: 'Table ('[] :=> Columns)
-- , "other_tab" ::: 'Table ('[] :=> Columns)
-- , "third_tab" ::: 'Table ('[] :=> Columns) ]
-- :}
--
--
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema3) () ()
-- manipulation =
-- deleteFrom #tab (Using (table #other_tab & also (table #third_tab)))
-- ( (#tab ! #col2 .== #other_tab ! #col2)
-- .&& (#tab ! #col2 .== #third_tab ! #col2) )
-- (Returning_ Nil)
-- in printSQL manipulation
-- :}
-- DELETE FROM "tab" USING "other_tab" AS "other_tab", "third_tab" AS "third_tab" WHERE (("tab"."col2" = "other_tab"."col2") AND ("tab"."col2" = "third_tab"."col2"))
--
--
-- with manipulation:
--
--
-- >>> type ProductsColumns = '["product" ::: 'NoDef :=> 'NotNull 'PGtext, "date" ::: 'Def :=> 'NotNull 'PGdate]
--
-- >>> type ProductsSchema = '["products" ::: 'Table ('[] :=> ProductsColumns), "products_deleted" ::: 'Table ('[] :=> ProductsColumns)]
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public ProductsSchema) (Only Day) ()
-- manipulation = with
-- (deleteFrom #products NoUsing (#date .< param @1) (Returning Star) `as` #del)
-- (insertInto_ #products_deleted (Subquery (select Star (from (common #del)))))
-- in printSQL manipulation
-- :}
-- 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)
-- | A Manipulation is a statement which may modify data in the
-- database, but does not alter its schemas. Examples are inserts,
-- updates and deletes. A Query is also considered a
-- Manipulation even though it does not modify data.
--
-- The general Manipulation type is parameterized by
--
-- -- >>> printSQL $ true `in_` [true, false, null_] -- TRUE IN (TRUE, FALSE, NULL) --in_ :: Expression outer commons grp schemas params from ty -> [Expression outer commons grp schemas params from ty] -> Condition outer commons grp schemas params from -- | The result is true if the left-hand expression's result is not -- equal to any of the right-hand expressions. -- --
-- >>> printSQL $ true `notIn` [false, null_] -- TRUE NOT IN (FALSE, NULL) --notIn :: Expression outer commons grp schemas params from ty -> [Expression outer commons grp schemas params from ty] -> Condition outer commons grp schemas params from -- | The right-hand side is a parenthesized subquery, which must return -- exactly one column. The left-hand expression is evaluated and compared -- to each row of the subquery result using the given Operator, -- which must yield a Boolean result. The result of subAll is -- true if all rows yield true (including the case where the -- subquery returns no rows). The result is false if any -- false result is found. The result is null_ if no -- comparison with a subquery row returns false, and at least one -- comparison returns null_. -- --
-- >>> printSQL $ subAll true (.==) (values_ (true `as` #foo))
-- (TRUE = ALL (SELECT * FROM (VALUES (TRUE)) AS t ("foo")))
--
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
-- | The right-hand side is a parenthesized subquery, which must return
-- exactly one column. The left-hand expression is evaluated and compared
-- to each row of the subquery result using the given Operator,
-- which must yield a Boolean result. The result of subAny is
-- true if any true result is obtained. The result is
-- false if no true result is found (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")))
--
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
-- | Set returning functions
module Squeal.PostgreSQL.Expression.SetOf
-- | -- 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] -- |
-- 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] -- |
-- 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] -- | 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 -- | 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. (SListI tys, KnownSymbol fun) => SetOfFunctionN fun tys setof -- | Array and composite functions module Squeal.PostgreSQL.Expression.Collection -- |
-- >>> printSQL $ array [null_, false, true] -- ARRAY[NULL, FALSE, TRUE] --array :: [Expression outer commons grp schemas params from ty] -> Expression outer commons grp schemas params from (null ( 'PGvararray ty)) -- | 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, All ((~) ty) tys) => NP (Expression outer commons grp schemas params from) tys -> Expression outer commons grp schemas params from (null ( 'PGfixarray '[n] ty))
-- | 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 :: (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))
-- | -- >>> printSQL $ cardinality (array [null_, false, true]) -- cardinality(ARRAY[NULL, FALSE, TRUE]) --cardinality :: null ( 'PGvararray ty) :--> null 'PGint8 -- |
-- >>> printSQL $ array [null_, false, true] & index 2 -- (ARRAY[NULL, FALSE, TRUE])[2] --index :: Word64 -> null ( 'PGvararray ty) :--> NullifyType ty -- | Expand an array to a set of rows unnest :: SetOfFunction "unnest" (null ( 'PGvararray ty)) '["unnest" ::: ty] -- | 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 :: SListI row => NP (Aliased (Expression outer commons grp schemas params from)) row -> Expression outer commons grp schemas params from (null ( 'PGcomposite row))
-- |
-- >>> :{
-- 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 -> Alias field -> Expression outer commons grp schemas params from ( 'NotNull ( 'PGcomposite row)) -> Expression outer commons grp schemas params from ty
-- | Json and Jsonb functions and operators
module Squeal.PostgreSQL.Expression.Json
-- | Get JSON value (object field or array element) at a key.
(.->) :: (json `In` PGJsonType, key `In` PGJsonKey) => Operator (null json) (null key) ( 'Null json)
infixl 8 .->
-- | Get JSON value (object field or array element) at a key, as text.
(.->>) :: (json `In` PGJsonType, key `In` PGJsonKey) => Operator (null json) (null key) ( 'Null 'PGtext)
infixl 8 .->>
-- | Get JSON value at a specified path.
(.#>) :: json `In` PGJsonType => Operator (null json) (null ( 'PGvararray ( 'NotNull 'PGtext))) ( 'Null json)
infixl 8 .#>
-- | Get JSON value at a specified path as text.
(.#>>) :: json `In` PGJsonType => Operator (null json) (null ( 'PGvararray ( 'NotNull 'PGtext))) ( 'Null 'PGtext)
infixl 8 .#>>
-- | Does the string exist as a top-level key within the JSON value?
(.?) :: Operator (null 'PGjsonb) (null 'PGtext) ( 'Null 'PGbool)
infixl 9 .?
-- | Do any of these array strings exist as top-level keys?
(.?|) :: Operator (null 'PGjsonb) (null ( 'PGvararray ( 'NotNull 'PGtext))) ( 'Null 'PGbool)
infixl 9 .?|
-- | Do all of these array strings exist as top-level keys?
(.?&) :: Operator (null 'PGjsonb) (null ( 'PGvararray ( 'NotNull 'PGtext))) ( 'Null 'PGbool)
infixl 9 .?&
-- | Delete a key or keys from a JSON object, or remove an array element.
--
-- If the right operand is
--
-- text : Delete key / value pair or string element from left
-- operand. Key / value pairs are matched based on their key value,
--
-- text[] : Delete multiple key / value pairs or string
-- elements from left operand. Key / value pairs are matched based on
-- their key value,
--
-- integer : Delete the array element with specified index
-- (Negative integers count from the end). Throws an error if top level
-- container is not an array.
(.-.) :: key `In` '[ 'PGtext, 'PGvararray ( 'NotNull 'PGtext), 'PGint4, 'PGint2] => Operator (null 'PGjsonb) (null key) (null 'PGjsonb)
infixl 6 .-.
-- | Delete the field or element with specified path (for JSON arrays,
-- negative integers count from the end)
(#-.) :: Operator (null 'PGjsonb) (null ( 'PGvararray ( 'NotNull 'PGtext))) (null 'PGjsonb)
infixl 6 #-.
-- | Returns the value as json. Arrays and composites are converted
-- (recursively) to arrays and objects; otherwise, if there is a cast
-- from the type to json, the cast function will be used to perform the
-- conversion; 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
-- | Returns the value as jsonb. Arrays and composites are converted
-- (recursively) to arrays and objects; otherwise, if there is a cast
-- from the type to json, the cast function will be used to perform the
-- conversion; 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
-- | Returns the array as a JSON array. A PostgreSQL multidimensional array
-- becomes a JSON array of arrays.
arrayToJson :: null ( 'PGvararray ty) :--> null 'PGjson
-- | Returns the row as a JSON object.
rowToJson :: null ( 'PGcomposite ty) :--> null 'PGjson
-- | Builds a possibly-heterogeneously-typed JSON array out of a variadic
-- argument list.
jsonBuildArray :: SListI tuple => FunctionN tuple (null 'PGjson)
-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
-- variadic argument list.
jsonbBuildArray :: SListI tuple => FunctionN tuple (null 'PGjsonb)
-- | Builds a possibly-heterogeneously-typed JSON object out of a variadic
-- argument list. The elements of the argument list must alternate
-- between text and values.
class SListI tys => JsonBuildObject tys
jsonBuildObject :: JsonBuildObject tys => FunctionN tys (null 'PGjson)
jsonbBuildObject :: JsonBuildObject tys => FunctionN tys (null 'PGjsonb)
-- | Builds a JSON object out of a text array. The array must have two
-- dimensions such that each inner array has exactly two elements, which
-- are taken as a key/value pair.
jsonObject :: null ( 'PGfixarray '[n, 2] ( 'NotNull 'PGtext)) :--> null 'PGjson
-- | Builds a binary JSON object out of a text array. The array must have
-- two dimensions such that each inner array has exactly two elements,
-- which are taken as a key/value pair.
jsonbObject :: null ( 'PGfixarray '[n, 2] ( 'NotNull 'PGtext)) :--> null 'PGjsonb
-- | 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 '[null ( 'PGvararray ( 'NotNull 'PGtext)), null ( 'PGvararray ( 'NotNull 'PGtext))] (null 'PGjson)
-- | 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 '[null ( 'PGvararray ( 'NotNull 'PGtext)), null ( 'PGvararray ( 'NotNull 'PGtext))] (null 'PGjsonb)
-- | Returns the number of elements in the outermost JSON array.
jsonArrayLength :: null 'PGjson :--> null 'PGint4
-- | Returns the number of elements in the outermost binary JSON array.
jsonbArrayLength :: null 'PGjsonb :--> null 'PGint4
-- | 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
-- | 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
-- | Returns its argument with all object fields that have null values
-- omitted. Other null values are untouched.
jsonStripNulls :: null 'PGjson :--> null 'PGjson
-- | Returns its argument with all object fields that have null values
-- omitted. Other null values are untouched.
jsonbStripNulls :: null 'PGjsonb :--> null 'PGjsonb
-- | -- jsonbSet target path new_value create_missing ---- -- Returns target with the section designated by path replaced by -- new_value, or with new_value added if create_missing -- is true and the 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) -- |
-- jsonbInsert target path new_value insert_after ---- -- Returns target with new_value inserted. If target section -- designated by path is in a JSONB array, new_value will be -- inserted before target or after if insert_after is -- true. If target section designated by 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) -- | Returns its argument as indented JSON text. jsonbPretty :: null 'PGjsonb :--> null 'PGtext -- | Expands the outermost JSON object into a set of key/value pairs. -- --
-- >>> printSQL (select Star (from (jsonEach (literal (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]
-- | 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"]))))))
-- SELECT * FROM jsonb_each(('{"a":"foo","b":"bar"}' :: jsonb))
--
jsonbEach :: SetOfFunction "jsonb_each" (nullity 'PGjsonb) '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson]
-- | Expands the outermost JSON object into a set of key/value pairs.
--
--
-- >>> printSQL (select Star (from (jsonEachText (literal (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]
-- | 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"]))))))
-- SELECT * FROM jsonb_each_text(('{"a":"foo","b":"bar"}' :: jsonb))
--
jsonbEachText :: SetOfFunction "jsonb_each_text" (null 'PGjsonb) '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext]
-- | Returns set of keys in the outermost JSON object.
--
--
-- >>> printSQL (jsonObjectKeys (literal (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]
-- | Returns set of keys in the outermost JSON object.
--
--
-- >>> printSQL (jsonbObjectKeys (literal (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]
-- | Build rows from Json types.
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]
-- | Expands the JSON expression to a row whose columns match the record
-- type defined by the given table.
jsonPopulateRecord :: JsonPopulateFunction "json_populate_record" 'PGjson
-- | Expands the binary JSON expression to a row whose columns match the
-- record type defined by the given table.
jsonbPopulateRecord :: JsonPopulateFunction "jsonb_populate_record" 'PGjsonb
-- | Expands the outermost array of objects in the given JSON expression to
-- a set of rows whose columns match the record type defined by the given
-- table.
jsonPopulateRecordSet :: JsonPopulateFunction "json_populate_record_set" 'PGjson
-- | Expands the outermost array of objects in the given binary JSON
-- expression to a set of rows whose columns match the record type
-- defined by the given table.
jsonbPopulateRecordSet :: JsonPopulateFunction "jsonb_populate_record_set" 'PGjsonb
-- | Build rows from Json types.
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]
-- | Builds an arbitrary record from a JSON object.
jsonToRecord :: JsonToRecordFunction 'PGjson
-- | Builds an arbitrary record from a binary JSON object.
jsonbToRecord :: JsonToRecordFunction 'PGjsonb
-- | Builds an arbitrary set of records from a JSON array of objects.
jsonToRecordSet :: JsonToRecordFunction 'PGjson
-- | Builds an arbitrary set of records from a binary JSON array of
-- objects.
jsonbToRecordSet :: JsonToRecordFunction 'PGjsonb
instance Squeal.PostgreSQL.Expression.Json.JsonBuildObject '[]
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 data definition language.
module Squeal.PostgreSQL.Definition
-- | A Definition is a statement that changes the schemas of the
-- database, like a createTable, dropTable, or
-- alterTable command. Definitions may be composed using
-- the >>> operator.
newtype Definition (schemas0 :: SchemasType) (schemas1 :: SchemasType)
UnsafeDefinition :: ByteString -> Definition
[renderDefinition] :: Definition -> ByteString
-- | Left-to-right composition
(>>>) :: Category cat => cat a b -> cat b c -> cat a c
infixr 1 >>>
-- | A Manipulation without input or output can be run as a
-- statement along with other Definitions, by embedding it using
-- manipDefinition.
manipDefinition :: Manipulation '[] schemas '[] '[] -> Definition schemas schemas
-- | 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 QualifiedAliases with the schema name
-- as a prefix.
createSchema :: KnownSymbol sch => Alias sch -> Definition schemas (Create sch '[] schemas)
-- | Idempotent version of createSchema.
createSchemaIfNotExists :: (KnownSymbol sch, Has sch schemas schema) => Alias sch -> Definition schemas schemas
-- | 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), 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
-- | 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 Definitions.
--
--
-- >>> :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)), SListI columns, SListI constraints) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression schemas)) columns -> NP (Aliased (TableConstraintExpression sch tab schemas)) constraints -> Definition schemas schemas
-- | 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 b :* 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 -> Query '[] '[] schemas '[] view -> Definition schemas (Alter sch (Create vw ( 'View view) schema) schemas)
-- | 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, All KnownSymbol labels) => QualifiedAlias sch enum -> NP PGlabel labels -> Definition schemas (Alter sch (Create enum ( 'Typedef ( 'PGenum labels)) schema) schemas)
-- | 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. (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)
-- | 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, SListI fields) => QualifiedAlias sch ty -> NP (Aliased (TypeExpression schemas)) fields -> Definition schemas (Alter sch (Create ty ( 'Typedef ( 'PGcomposite fields)) schema) schemas)
-- | 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. (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)
-- | Lift PGTyped to a field
class FieldTyped schemas ty
fieldtype :: FieldTyped schemas ty => Aliased (TypeExpression schemas) ty
-- | 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)
-- | 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.
-- TableConstraints 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 :: ByteString -> TableConstraintExpression
[renderTableConstraintExpression] :: TableConstraintExpression -> ByteString
-- | 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 -> (forall t. Condition '[] '[] 'Ungrouped schemas '[] '[t ::: subcolumns]) -> TableConstraintExpression sch tab schemas ( 'Check aliases)
-- | 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 -> TableConstraintExpression sch tab schemas ( 'Unique aliases)
-- | 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 -> TableConstraintExpression sch tab schemas ( 'PrimaryKey aliases)
-- | 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 -> Alias parent -> NP Alias refcolumns -> OnDeleteClause -> OnUpdateClause -> TableConstraintExpression sch child schemas ( 'ForeignKey columns parent refcolumns)
-- | 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, AllZip SamePGType tys reftys, Uniquely refcolumns constraints)
-- | OnDeleteClause indicates what to do with rows that reference a
-- deleted row.
data OnDeleteClause
-- | if any referencing rows still exist when the constraint is checked, an
-- error is raised
OnDeleteNoAction :: OnDeleteClause
-- | prevents deletion of a referenced row
OnDeleteRestrict :: OnDeleteClause
-- | specifies that when a referenced row is deleted, row(s) referencing it
-- should be automatically deleted as well
OnDeleteCascade :: OnDeleteClause
-- | Analagous to OnDeleteClause there is also OnUpdateClause
-- which is invoked when a referenced column is changed (updated).
data OnUpdateClause
-- | if any referencing rows has not changed when the constraint is
-- checked, an error is raised
OnUpdateNoAction :: OnUpdateClause
-- | prevents update of a referenced row
OnUpdateRestrict :: OnUpdateClause
-- | the updated values of the referenced column(s) should be copied into
-- the referencing row(s)
OnUpdateCascade :: OnUpdateClause
-- |
-- >>> :{
-- 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) -- | 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 -> Definition schemas (Alter sch (Drop tab schema) schemas) -- | 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 -> Definition schemas (Alter sch (Drop vw schema) schemas)
-- | 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 -> Definition schemas (Alter sch (Drop td schema) schemas) -- | alterTable changes the definition of a table from the schema. 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) -- | 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 -> Alias table1 -> Definition schema (Rename table0 table1 schema) -- | An AlterTable describes the alteration to perform on the -- columns of a table. newtype AlterTable (sch :: Symbol) (tab :: Symbol) (schemas :: SchemasType) (table :: TableType) UnsafeAlterTable :: ByteString -> AlterTable [renderAlterTable] :: AlterTable -> ByteString -- | 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 -> AlterTable sch tab schemas table1
-- | 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 -> AlterTable sch tab schemas table1
-- | An AddColumn is either NULL or has DEFAULT.
class AddColumn ty
-- | 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 :: (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)
-- | 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 -> AlterTable sch tab schemas table1
-- | 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 -> Alias column1 -> AlterTable sch tab schemas table1
-- | 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 -> AlterColumn schemas ty0 ty1 -> AlterTable sch tab schemas table1
-- | An AlterColumn describes the alteration to perform on a single
-- column.
newtype AlterColumn (schemas :: SchemasType) (ty0 :: ColumnType) (ty1 :: ColumnType)
UnsafeAlterColumn :: ByteString -> AlterColumn
[renderAlterColumn] :: AlterColumn -> ByteString
-- | 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 -> AlterColumn schemas (constraint :=> ty) ( 'Def :=> ty)
-- | 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)
-- | 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)
-- | 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)
-- | 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
-- | ColumnTypeExpressions are used in createTable commands.
newtype ColumnTypeExpression (schemas :: SchemasType) (ty :: ColumnType)
UnsafeColumnTypeExpression :: ByteString -> ColumnTypeExpression
[renderColumnTypeExpression] :: ColumnTypeExpression -> ByteString
-- | 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)
-- | 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)
-- | 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)
-- | not a true type, but merely a notational convenience for creating
-- unique identifier columns with type PGint2
serial2 :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint2)
-- | not a true type, but merely a notational convenience for creating
-- unique identifier columns with type PGint2
smallserial :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint2)
-- | not a true type, but merely a notational convenience for creating
-- unique identifier columns with type PGint4
serial4 :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint4)
-- | not a true type, but merely a notational convenience for creating
-- unique identifier columns with type PGint4
serial :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint4)
-- | not a true type, but merely a notational convenience for creating
-- unique identifier columns with type PGint8
serial8 :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint8)
-- | not a true type, but merely a notational convenience for creating
-- unique identifier columns with type PGint8
bigserial :: ColumnTypeExpression schemas ( 'Def :=> 'NotNull 'PGint8)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.AlterColumn schemas ty0 ty1)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.AlterTable sch tab schemas table)
instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.OnUpdateClause
instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.OnUpdateClause
instance GHC.Show.Show Squeal.PostgreSQL.Definition.OnUpdateClause
instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.OnUpdateClause
instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.OnDeleteClause
instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.OnDeleteClause
instance GHC.Show.Show Squeal.PostgreSQL.Definition.OnDeleteClause
instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.OnDeleteClause
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
instance Squeal.PostgreSQL.Definition.AddColumn ('Squeal.PostgreSQL.Schema.Def Squeal.PostgreSQL.Schema.:=> ty)
instance Squeal.PostgreSQL.Definition.AddColumn ('Squeal.PostgreSQL.Schema.NoDef Squeal.PostgreSQL.Schema.:=> 'Squeal.PostgreSQL.Schema.Null ty)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.ColumnTypeExpression schemas ty)
instance (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Expression.Type.PGTyped schemas ty) => Squeal.PostgreSQL.Definition.FieldTyped schemas (alias Squeal.PostgreSQL.Alias.::: ty)
instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.OnUpdateClause
instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.OnUpdateClause
instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.OnDeleteClause
instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.OnDeleteClause
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.TableConstraintExpression sch tab schemas constraint)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Definition schemas0 schemas1)
instance Control.Category.Category Squeal.PostgreSQL.Definition.Definition
-- | This module provides binary encoding and decoding between Haskell and
-- PostgreSQL types.
--
-- Instances are governed by the Generic and
-- 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 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
--
module Squeal.PostgreSQL.Binary
-- | 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)
-- | -- >>> :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 :: ToParam x pg => x -> K Encoding pg
-- | A ToParams constraint generically sequences the encodings of
-- Types of the fields of a tuple or record to a row of
-- ColumnTypes. You should not define instances of
-- ToParams. Instead define Generic instances which in turn
-- provide ToParams instances.
class SListI tys => ToParams (x :: Type) (tys :: [NullityType])
-- | -- >>> 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 :: ToParams x tys => x -> NP (K (Maybe Encoding)) tys
-- | 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)
toNullityParam :: ToNullityParam x ty => x -> K (Maybe Encoding) ty
-- | A ToField constraint lifts the ToParam parser to an
-- encoding of a (Symbol, Type) to a (Symbol,
-- NullityType), encoding Nulls to Maybes. You should
-- not define instances for FromField, just use the provided
-- instances.
class ToField (x :: (Symbol, Type)) (field :: (Symbol, NullityType))
toField :: ToField x field => P x -> K (Maybe Encoding) field
-- | 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)
toFixArray :: ToFixArray x dims array => x -> K (K Array dims) array
-- | A FromValue constraint gives a parser from the binary format of
-- a PostgreSQL PGType into a Haskell Type.
class FromValue (pg :: PGType) (y :: Type)
-- |
-- >>> newtype Id = Id { getId :: Int16 } deriving Show
--
-- >>> instance FromValue 'PGint2 Id where fromValue = Id <$> fromValue @'PGint2
--
fromValue :: FromValue pg y => Value 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 Generic and
-- HasDatatypeInfo instances which in turn provide FromRow
-- instances.
class SListI result => FromRow (result :: RowType) y
-- |
-- >>> :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 :: FromRow result y => NP (K (Maybe ByteString)) result -> Either Text y
-- | A FromField constraint lifts the FromValue parser to a
-- decoding of a (Symbol, NullityType) to a Type,
-- decoding Nulls to Maybes. You should not define
-- instances for FromField, just use the provided instances.
class FromField (pg :: (Symbol, NullityType)) (y :: (Symbol, Type))
fromField :: FromField pg y => K (Maybe ByteString) pg -> (Either Text :.: P) y
-- | 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)
fromFixArray :: FromFixArray dims ty y => Array y
-- | 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 :: x -> Only x
[fromOnly] :: Only x -> x
-- | The object identifier of a PGType.
--
-- -- >>> :set -XTypeApplications -- -- >>> oid @'PGbool -- 16 --class HasOid (ty :: PGType) oid :: HasOid ty => Word32 -- | Lifts a HasOid constraint to a field. class HasAliasedOid (field :: (Symbol, NullityType)) aliasedOid :: HasAliasedOid field => Word32 instance GHC.Generics.Generic (Squeal.PostgreSQL.Binary.Only x) instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Binary.Only x) instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Binary.Only x) instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Binary.Only x) instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Binary.Only x) instance Data.Traversable.Traversable Squeal.PostgreSQL.Binary.Only instance Data.Foldable.Foldable Squeal.PostgreSQL.Binary.Only instance GHC.Base.Functor Squeal.PostgreSQL.Binary.Only instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Binary.Only x) instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Binary.Only x) instance Squeal.PostgreSQL.Binary.FromRow fields y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGcomposite fields) (Squeal.PostgreSQL.PG.Composite y) 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 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)) 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))) 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]) 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]) instance Squeal.PostgreSQL.Binary.FromFixArray dims ty y => Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGfixarray dims ty) (Squeal.PostgreSQL.PG.FixArray y) instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromFixArray '[] ('Squeal.PostgreSQL.Schema.NotNull pg) y instance Squeal.PostgreSQL.Binary.FromValue pg y => Squeal.PostgreSQL.Binary.FromFixArray '[] ('Squeal.PostgreSQL.Schema.Null pg) (GHC.Maybe.Maybe y) 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 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) 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) instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGbool GHC.Types.Bool instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGint2 GHC.Int.Int16 instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGint4 GHC.Int.Int32 instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGint8 GHC.Int.Int64 instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGfloat4 GHC.Types.Float instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGfloat8 GHC.Types.Double instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGnumeric Data.Scientific.Scientific instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGmoney Squeal.PostgreSQL.PG.Money instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGuuid Data.UUID.Types.Internal.UUID instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGinet (Network.IP.Addr.NetAddr Network.IP.Addr.IP) instance Squeal.PostgreSQL.Binary.FromValue ('Squeal.PostgreSQL.Schema.PGchar 1) GHC.Types.Char instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtext Data.Text.Internal.Text instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtext Data.Text.Internal.Lazy.Text instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtext GHC.Base.String instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGbytea Data.ByteString.Internal.ByteString instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGbytea Data.ByteString.Lazy.Internal.ByteString instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGdate Data.Time.Calendar.Days.Day instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtime Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtimetz (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone) instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtimestamp Data.Time.LocalTime.Internal.LocalTime.LocalTime instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGtimestamptz Data.Time.Clock.Internal.UTCTime.UTCTime instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGinterval Data.Time.Clock.Internal.DiffTime.DiffTime instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjson Data.Aeson.Types.Internal.Value instance Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjsonb Data.Aeson.Types.Internal.Value instance Data.Aeson.Types.FromJSON.FromJSON x => Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjson (Squeal.PostgreSQL.PG.Json x) instance Data.Aeson.Types.FromJSON.FromJSON x => Squeal.PostgreSQL.Binary.FromValue 'Squeal.PostgreSQL.Schema.PGjsonb (Squeal.PostgreSQL.PG.Jsonb x) 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) 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 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) instance Squeal.PostgreSQL.Binary.ToNullityParam x ty => Squeal.PostgreSQL.Binary.ToFixArray x '[] ty 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 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) instance Squeal.PostgreSQL.Binary.ToNullityParam x ty => Squeal.PostgreSQL.Binary.ToField (alias Squeal.PostgreSQL.Alias.::: x) (alias Squeal.PostgreSQL.Alias.::: ty) 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) instance Squeal.PostgreSQL.Binary.ToParam x pg => Squeal.PostgreSQL.Binary.ToNullityParam x ('Squeal.PostgreSQL.Schema.NotNull pg) instance Squeal.PostgreSQL.Binary.ToParam x pg => Squeal.PostgreSQL.Binary.ToNullityParam (GHC.Maybe.Maybe x) ('Squeal.PostgreSQL.Schema.Null pg) instance Squeal.PostgreSQL.Binary.HasOid ty => Squeal.PostgreSQL.Binary.HasAliasedOid (alias Squeal.PostgreSQL.Alias.::: nullity ty) 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)) 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)) instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGbool instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGint2 instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGint4 instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGint8 instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGnumeric instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGfloat4 instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGfloat8 instance Squeal.PostgreSQL.Binary.HasOid ('Squeal.PostgreSQL.Schema.PGchar n) instance Squeal.PostgreSQL.Binary.HasOid ('Squeal.PostgreSQL.Schema.PGvarchar n) instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtext instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGbytea instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtimestamp instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtimestamptz instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGdate instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtime instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGtimetz instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGuuid instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGinet instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGjson instance Squeal.PostgreSQL.Binary.HasOid 'Squeal.PostgreSQL.Schema.PGjsonb instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Bool 'Squeal.PostgreSQL.Schema.PGbool instance Squeal.PostgreSQL.Binary.ToParam GHC.Int.Int16 'Squeal.PostgreSQL.Schema.PGint2 instance Squeal.PostgreSQL.Binary.ToParam GHC.Word.Word16 'Squeal.PostgreSQL.Schema.PGint2 instance Squeal.PostgreSQL.Binary.ToParam GHC.Int.Int32 'Squeal.PostgreSQL.Schema.PGint4 instance Squeal.PostgreSQL.Binary.ToParam GHC.Word.Word32 'Squeal.PostgreSQL.Schema.PGint4 instance Squeal.PostgreSQL.Binary.ToParam GHC.Int.Int64 'Squeal.PostgreSQL.Schema.PGint8 instance Squeal.PostgreSQL.Binary.ToParam GHC.Word.Word64 'Squeal.PostgreSQL.Schema.PGint8 instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Float 'Squeal.PostgreSQL.Schema.PGfloat4 instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Double 'Squeal.PostgreSQL.Schema.PGfloat8 instance Squeal.PostgreSQL.Binary.ToParam Data.Scientific.Scientific 'Squeal.PostgreSQL.Schema.PGnumeric instance Squeal.PostgreSQL.Binary.ToParam Squeal.PostgreSQL.PG.Money 'Squeal.PostgreSQL.Schema.PGmoney instance Squeal.PostgreSQL.Binary.ToParam Data.UUID.Types.Internal.UUID 'Squeal.PostgreSQL.Schema.PGuuid instance Squeal.PostgreSQL.Binary.ToParam (Network.IP.Addr.NetAddr Network.IP.Addr.IP) 'Squeal.PostgreSQL.Schema.PGinet instance Squeal.PostgreSQL.Binary.ToParam GHC.Types.Char ('Squeal.PostgreSQL.Schema.PGchar 1) instance Squeal.PostgreSQL.Binary.ToParam Data.Text.Internal.Text 'Squeal.PostgreSQL.Schema.PGtext instance Squeal.PostgreSQL.Binary.ToParam Data.Text.Internal.Lazy.Text 'Squeal.PostgreSQL.Schema.PGtext instance Squeal.PostgreSQL.Binary.ToParam GHC.Base.String 'Squeal.PostgreSQL.Schema.PGtext instance Squeal.PostgreSQL.Binary.ToParam Data.ByteString.Internal.ByteString 'Squeal.PostgreSQL.Schema.PGbytea instance Squeal.PostgreSQL.Binary.ToParam Data.ByteString.Lazy.Internal.ByteString 'Squeal.PostgreSQL.Schema.PGbytea instance Squeal.PostgreSQL.Binary.ToParam Data.Time.Calendar.Days.Day 'Squeal.PostgreSQL.Schema.PGdate instance Squeal.PostgreSQL.Binary.ToParam Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay 'Squeal.PostgreSQL.Schema.PGtime instance Squeal.PostgreSQL.Binary.ToParam (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone) 'Squeal.PostgreSQL.Schema.PGtimetz instance Squeal.PostgreSQL.Binary.ToParam Data.Time.LocalTime.Internal.LocalTime.LocalTime 'Squeal.PostgreSQL.Schema.PGtimestamp instance Squeal.PostgreSQL.Binary.ToParam Data.Time.Clock.Internal.UTCTime.UTCTime 'Squeal.PostgreSQL.Schema.PGtimestamptz instance Squeal.PostgreSQL.Binary.ToParam Data.Time.Clock.Internal.DiffTime.DiffTime 'Squeal.PostgreSQL.Schema.PGinterval instance Squeal.PostgreSQL.Binary.ToParam Data.Aeson.Types.Internal.Value 'Squeal.PostgreSQL.Schema.PGjson instance Squeal.PostgreSQL.Binary.ToParam Data.Aeson.Types.Internal.Value 'Squeal.PostgreSQL.Schema.PGjsonb instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Json x) 'Squeal.PostgreSQL.Schema.PGjson instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Binary.ToParam (Squeal.PostgreSQL.PG.Jsonb x) 'Squeal.PostgreSQL.Schema.PGjsonb 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) -- | This module is where Squeal commands actually get executed by -- 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 -- Result of executing Squeal commands. module Squeal.PostgreSQL.PQ -- | Connection encapsulates a connection to the backend. data Connection -- | 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 -> io (K Connection schemas) -- | Closes the connection to the server. finish :: MonadIO io => K Connection schemas -> io () -- | 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 -- | Safely lowerConnection to a smaller schema. lowerConnection :: K Connection (schema : schemas) -> K Connection schemas -- | 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 :: (K Connection schemas0 -> m (K x schemas1)) -> PQ [unPQ] :: PQ -> K Connection schemas0 -> m (K x schemas1) -- | Run a PQ and keep the result and the Connection. runPQ :: Functor m => PQ schemas0 schemas1 m x -> K Connection schemas0 -> m (x, K Connection schemas1) -- | Execute a PQ and discard the result but keep the -- Connection. execPQ :: Functor m => PQ schemas0 schemas1 m x -> K Connection schemas0 -> m (K Connection schemas1) -- | Evaluate a PQ and discard the Connection but keep the -- result. evalPQ :: Functor m => PQ schemas0 schemas1 m x -> K Connection schemas0 -> m x -- | An Atkey indexed monad is a Functor 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 Definitions -- using define. class IndexedMonadTransPQ pq -- | indexed analog of <*> pqAp :: (IndexedMonadTransPQ pq, Monad m) => pq schemas0 schemas1 m (x -> y) -> pq schemas1 schemas2 m x -> pq schemas0 schemas2 m y -- | indexed analog of join pqJoin :: (IndexedMonadTransPQ pq, Monad m) => pq schemas0 schemas1 m (pq schemas1 schemas2 m y) -> pq schemas0 schemas2 m y -- | indexed analog of =<< pqBind :: (IndexedMonadTransPQ pq, Monad m) => (x -> pq schemas1 schemas2 m y) -> pq schemas0 schemas1 m x -> pq schemas0 schemas2 m y -- | indexed analog of flipped >> pqThen :: (IndexedMonadTransPQ pq, Monad m) => pq schemas1 schemas2 m y -> pq schemas0 schemas1 m x -> pq schemas0 schemas2 m y -- | indexed analog of <=< pqAndThen :: (IndexedMonadTransPQ pq, Monad m) => (y -> pq schemas1 schemas2 m z) -> (x -> pq schemas0 schemas1 m y) -> x -> pq schemas0 schemas2 m z -- | Run a Definition with exec. -- -- It should be functorial in effect. -- -- define id = return () define (statement1 >>> -- statement2) = define statement1 & pqThen (define statement2) define :: (IndexedMonadTransPQ pq, MonadIO io) => Definition schemas0 schemas1 -> pq schemas0 schemas1 io () -- | MonadPQ is an mtl style constraint, similar to -- MonadState, for using LibPQ to -- --
-- >>> import Squeal.PostgreSQL
--
-- >>> :{
-- do
-- let
-- query :: Query_ (Public '[]) () (Only Char)
-- query = values_ $ literal 'a' `as` #fromOnly
-- session :: PoolPQ (Public '[]) IO Char
-- session = do
-- result <- runQuery query
-- Just (Only chr) <- firstRow result
-- return chr
-- pool <- createConnectionPool "host=localhost port=5432 dbname=exampledb" 1 0.5 10
-- chr <- runPoolPQ session pool
-- destroyAllResources pool
-- putChar chr
-- :}
-- a
--
newtype PoolPQ (schemas :: SchemasType) m x
PoolPQ :: (Pool (K Connection schemas) -> m x) -> PoolPQ m x
[runPoolPQ] :: PoolPQ m x -> Pool (K Connection schemas) -> m x
-- | 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 -> Int -> NominalDiffTime -> Int -> io (Pool (K Connection schemas))
type Pool = Pool
destroyAllResources :: MonadUnliftIO m => Pool a -> m ()
instance GHC.Base.Functor m => GHC.Base.Functor (Squeal.PostgreSQL.Pool.PoolPQ schemas m)
instance GHC.Base.Monad m => GHC.Base.Applicative (Squeal.PostgreSQL.Pool.PoolPQ schemas m)
instance GHC.Base.Monad m => GHC.Base.Monad (Squeal.PostgreSQL.Pool.PoolPQ schemas m)
instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (Squeal.PostgreSQL.Pool.PoolPQ schemas m)
instance Control.Monad.Trans.Class.MonadTrans (Squeal.PostgreSQL.Pool.PoolPQ schemas)
instance Control.Monad.IO.Unlift.MonadUnliftIO io => Squeal.PostgreSQL.PQ.MonadPQ schemas (Squeal.PostgreSQL.Pool.PoolPQ schemas io)
instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Squeal.PostgreSQL.Pool.PoolPQ schemas m)
instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Squeal.PostgreSQL.Pool.PoolPQ schemas m)
-- | Literal expressions
module Squeal.PostgreSQL.Expression.Literal
-- | 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 literal :: Literal hask => hask -> Expr (null (PG hask)) instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Bool instance Data.Aeson.Types.ToJSON.ToJSON hask => Squeal.PostgreSQL.Expression.Literal.Literal (Squeal.PostgreSQL.PG.Json hask) instance Data.Aeson.Types.ToJSON.ToJSON hask => Squeal.PostgreSQL.Expression.Literal.Literal (Squeal.PostgreSQL.PG.Jsonb hask) instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Char instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Base.String instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Int.Int16 instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Int.Int32 instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Int.Int64 instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Float instance Squeal.PostgreSQL.Expression.Literal.Literal GHC.Types.Double instance Squeal.PostgreSQL.Expression.Literal.Literal Data.Text.Internal.Text instance Squeal.PostgreSQL.Expression.Literal.Literal Data.Text.Internal.Lazy.Text 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 transaction control language. module Squeal.PostgreSQL.Transaction -- | 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 -> tx x -- | Run a computation transactionally_, in defaultMode. transactionally_ :: (MonadUnliftIO tx, MonadPQ schemas tx) => tx x -> tx x -- | transactionallyRetry a computation; -- --
-- >>> :set -XDataKinds -XOverloadedLabels -- -- >>> :set -XOverloadedStrings -XFlexibleContexts -XTypeOperators ---- -- Next, let's define our TableTypes. -- --
-- >>> :{
-- 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 Migrations 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 Migrations using pure SQL -- Definitions for the up and down instructions, you -- can also perform impure IO actions by using a Migrations -- over the Terminally PQ IO category. module Squeal.PostgreSQL.Migration -- | 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 :: Text -> p schemas0 schemas1 -> p schemas1 schemas0 -> Migration p schemas0 schemas1 -- | The name of a Migration. Each name in a -- Migration should be unique. [name] :: Migration p schemas0 schemas1 -> Text -- | The up instruction of a Migration. [up] :: Migration p schemas0 schemas1 -> p schemas0 schemas1 -- | The down instruction of a Migration. [down] :: Migration p schemas0 schemas1 -> p schemas1 schemas0 -- | A Migratory p is a Category for which one can -- execute or rewind an AlignedList of Migrations over -- p. This includes the category of pure SQL Definitions -- and the category of impure Terminally PQ IO -- actions. class Category p => Migratory p -- | Run an AlignedList of Migrations. 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 :: Migratory p => AlignedList (Migration p) schemas0 schemas1 -> PQ schemas0 schemas1 IO () -- | Rewind an AlignedList of Migrations. 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 :: Migratory p => AlignedList (Migration p) schemas0 schemas1 -> PQ schemas1 schemas0 IO () -- | 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 :: trans x0 x1 monad () -> Terminally trans monad x0 x1 [runTerminally] :: Terminally trans monad x0 x1 -> trans x0 x1 monad () -- | 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 -- | A pureMigration turns a Migration involving only pure -- SQL Definitions into a Migration that may be combined -- with arbitrary IO. pureMigration :: Migration Definition schemas0 schemas1 -> Migration (Terminally PQ IO) schemas0 schemas1 -- | The TableType for a Squeal migration. type MigrationsTable = '["migrations_unique_name" ::: 'Unique '["name"]] :=> '["name" ::: 'NoDef :=> 'NotNull 'PGtext, "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz] -- | defaultMain creates a simple executable from a connection -- string and a list of Migrations. defaultMain :: Migratory p => ByteString -> AlignedList (Migration p) db0 db1 -> IO () instance GHC.Show.Show Squeal.PostgreSQL.Migration.MigrateCommand instance GHC.Generics.Generic Squeal.PostgreSQL.Migration.MigrateCommand instance GHC.Show.Show Squeal.PostgreSQL.Migration.MigrationRow instance GHC.Generics.Generic Squeal.PostgreSQL.Migration.MigrationRow 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) instance forall k (p :: k -> k -> *) (schemas0 :: k) (schemas1 :: k). GHC.Generics.Generic (Squeal.PostgreSQL.Migration.Migration p schemas0 schemas1) instance Squeal.PostgreSQL.Migration.Migratory (Squeal.PostgreSQL.Migration.Terminally Squeal.PostgreSQL.PQ.PQ GHC.Types.IO) instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Migration.MigrationRow instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Migration.MigrationRow 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) instance Squeal.PostgreSQL.Migration.Migratory Squeal.PostgreSQL.Definition.Definition -- | Squeal is a deep embedding of PostgreSQL in Haskell. Let's see -- an example! -- -- First, we need some language extensions because Squeal uses modern GHC -- features. -- --
-- >>> :set -XDataKinds -XDeriveGeneric -XOverloadedLabels -XFlexibleContexts -- -- >>> :set -XOverloadedStrings -XTypeApplications -XTypeOperators -XGADTs ---- -- We'll need some imports. -- --
-- >>> import Control.Monad.IO.Class (liftIO) -- -- >>> import Data.Int (Int32) -- -- >>> import Data.Text (Text) -- -- >>> import Squeal.PostgreSQL ---- -- We'll use generics to easily convert between Haskell and PostgreSQL -- values. -- --
-- >>> import qualified Generics.SOP as SOP -- -- >>> import qualified GHC.Generics as GHC ---- -- The first step is to define the schema of our database. This is where -- we use DataKinds and TypeOperators. -- --
-- >>> :{
-- type UsersColumns =
-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
-- , "name" ::: 'NoDef :=> 'NotNull 'PGtext ]
-- type UsersConstraints = '[ "pk_users" ::: 'PrimaryKey '["id"] ]
-- type EmailsColumns =
-- '[ "id" ::: 'Def :=> 'NotNull 'PGint4
-- , "user_id" ::: 'NoDef :=> 'NotNull 'PGint4
-- , "email" ::: 'NoDef :=> 'Null 'PGtext ]
-- type EmailsConstraints =
-- '[ "pk_emails" ::: 'PrimaryKey '["id"]
-- , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"] ]
-- type Schema =
-- '[ "users" ::: 'Table (UsersConstraints :=> UsersColumns)
-- , "emails" ::: 'Table (EmailsConstraints :=> EmailsColumns) ]
-- type Schemas = Public Schema
-- :}
--
--
-- Notice the use of type operators.
--
-- ::: is used to pair an alias Symbol with a
-- SchemasType, a SchemumType, a TableConstraint or
-- a ColumnType. It is intended to connote Haskell's ::
-- operator.
--
-- :=> is used to pair TableConstraints with a
-- ColumnsType, yielding a TableType, or to pair a
-- ColumnConstraint with a NullityType, yielding a
-- ColumnType. It is intended to connote Haskell's =>
-- operator
--
-- Next, we'll write Definitions to set up and tear down the
-- schema. In Squeal, a Definition like createTable,
-- alterTable or dropTable has two type parameters,
-- corresponding to the schema before being run and the schema after. We
-- can compose definitions using >>>. Here and in the
-- rest of our commands we make use of overloaded labels to refer to
-- named tables and columns in our schema.
--
--
-- >>> :{
-- let
-- setup :: Definition (Public '[]) Schemas
-- 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 )
-- :}
--
--
-- We can easily see the generated SQL is unsurprising looking.
--
--
-- >>> 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);
--
--
-- Notice that setup starts with an empty public schema
-- (Public '[]) and produces Schemas. In our
-- createTable commands we included TableConstraints to
-- define primary and foreign keys, making them somewhat complex. Our
-- teardown Definition is simpler.
--
--
-- >>> :{
-- let
-- teardown :: Definition Schemas (Public '[])
-- teardown = dropTable #emails >>> dropTable #users
-- :}
--
--
-- -- >>> printSQL teardown -- DROP TABLE "emails"; -- DROP TABLE "users"; ---- -- We'll need a Haskell type for Users. We give the type -- Generic and HasDatatypeInfo instances so that we can -- encode and decode Users. -- --
-- >>> data User = User { userName :: Text, userEmail :: Maybe Text } deriving (Show, GHC.Generic)
--
-- >>> instance SOP.Generic User
--
-- >>> instance SOP.HasDatatypeInfo User
--
--
-- Next, we'll write Manipulation_s to insert Users 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 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.
--
--
-- >>> :{
-- let
-- insertUser :: Manipulation_ Schemas User ()
-- insertUser = with (u `as` #u) e
-- where
-- u = insertInto #users
-- (Values_ (Default `as` #id :* Set (param @1) `as` #name))
-- OnConflictDoRaise (Returning_ (#id :* param @2 `as` #email))
-- e = insertInto_ #emails $ Select
-- (Default `as` #id :* Set (#u ! #id) `as` #user_id :* Set (#u ! #email) `as` #email)
-- (from (common #u))
-- :}
--
--
--
-- >>> 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 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.
--
--
-- >>> :{
-- let
-- getUsers :: Query_ Schemas () User
-- getUsers = select_
-- (#u ! #name `as` #userName :* #e ! #email `as` #userEmail)
-- ( from (table (#users `as` #u)
-- & innerJoin (table (#emails `as` #e))
-- (#u ! #id .== #e ! #user_id)) )
-- :}
--
--
--
-- >>> printSQL getUsers
-- SELECT "u"."name" AS "userName", "e"."email" AS "userEmail" FROM "users" AS "u" INNER JOIN "emails" AS "e" ON ("u"."id" = "e"."user_id")
--
--
-- Let's create some users to add to the database.
--
--
-- >>> :{
-- let
-- users :: [User]
-- users =
-- [ User "Alice" (Just "alice@gmail.com")
-- , User "Bob" Nothing
-- , User "Carole" (Just "carole@hotmail.com")
-- ]
-- :}
--
--
-- Now we can put together all the pieces into a program. The program
-- connects to the database, sets up the schema, inserts the user data
-- (using prepared statements as an optimization), queries the user data
-- and prints it out and finally closes the connection. We can thread the
-- changing schema information through by using the indexed PQ
-- monad transformer and when the schema doesn't change we can use
-- Monad and MonadPQ functionality.
--
--
-- >>> :{
-- let
-- session :: PQ Schemas Schemas IO ()
-- session = do
-- _ <- traversePrepared_ insertUser users
-- usersResult <- runQuery getUsers
-- usersRows <- getRows usersResult
-- liftIO $ print (usersRows :: [User])
-- in
-- withConnection "host=localhost port=5432 dbname=exampledb" $
-- define setup
-- & pqThen session
-- & pqThen (define teardown)
-- :}
-- [User {userName = "Alice", userEmail = Just "alice@gmail.com"},User {userName = "Bob", userEmail = Nothing},User {userName = "Carole", userEmail = Just "carole@hotmail.com"}]
--
module Squeal.PostgreSQL
-- | A class for rendering SQL
class RenderSQL sql
renderSQL :: RenderSQL sql => sql -> ByteString
-- | Print SQL.
printSQL :: (RenderSQL sql, MonadIO io) => sql -> io ()