-- 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.6.0.1 -- | render 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 -- | Escape quote a string. escapeQuotedString :: String -> ByteString -- | Escape quote a string. escapeQuotedText :: Text -> 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 -- | exceptions module Squeal.PostgreSQL.Session.Exception -- | Exceptions that can be thrown by Squeal. data SquealException -- | SQL exception state SQLException :: SQLState -> SquealException -- | LibPQ function connection exception ConnectionException :: Text -> SquealException -- | decoding exception function and error message DecodingException :: Text -> Text -> SquealException -- | unexpected number of columns ColumnsException :: Text -> Column -> SquealException -- | too few rows, expected at least and actual number of rows RowsException :: Text -> Row -> Row -> SquealException -- | A pattern for unique violation exceptions. pattern UniqueViolation :: ByteString -> SquealException -- | A pattern for check constraint violation exceptions. pattern CheckViolation :: ByteString -> SquealException -- | A pattern for serialization failure exceptions. pattern SerializationFailure :: ByteString -> SquealException -- | the state of LibPQ data SQLState SQLState :: ExecStatus -> ByteString -> ByteString -> SQLState [sqlExecStatus] :: SQLState -> ExecStatus -- | -- https://www.postgresql.org/docs/current/static/errcodes-appendix.html [sqlStateCode] :: SQLState -> ByteString [sqlErrorMessage] :: SQLState -> ByteString data ExecStatus -- | The string sent to the server was empty. EmptyQuery :: ExecStatus -- | Successful completion of a command returning no data. CommandOk :: ExecStatus -- | Successful completion of a command returning data (such as a SELECT or -- SHOW). TuplesOk :: ExecStatus -- | Copy Out (from server) data transfer started. CopyOut :: ExecStatus -- | Copy In (to server) data transfer started. CopyIn :: ExecStatus -- | Copy In/Out data transfer started. CopyBoth :: ExecStatus -- | The server's response was not understood. BadResponse :: ExecStatus -- | A nonfatal error (a notice or warning) occurred. NonfatalError :: ExecStatus -- | A fatal error occurred. FatalError :: ExecStatus -- | The PGresult contains a single result tuple from the current command. -- This status occurs only when single-row mode has been selected for the -- query. SingleTuple :: ExecStatus -- | Catch SquealExceptions. catchSqueal :: MonadUnliftIO io => io a -> (SquealException -> io a) -> io a -- | Handle SquealExceptions. handleSqueal :: MonadUnliftIO io => (SquealException -> io a) -> io a -> io a -- | Either return a SquealException or a result. trySqueal :: MonadUnliftIO io => io a -> io (Either SquealException a) -- | Throw SquealExceptions. throwSqueal :: MonadUnliftIO io => SquealException -> io a instance GHC.Show.Show Squeal.PostgreSQL.Session.Exception.SquealException instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Exception.SquealException instance GHC.Show.Show Squeal.PostgreSQL.Session.Exception.SQLState instance GHC.Classes.Eq Squeal.PostgreSQL.Session.Exception.SQLState instance GHC.Exception.Type.Exception Squeal.PostgreSQL.Session.Exception.SquealException -- | types module Squeal.PostgreSQL.Type -- | The Money newtype stores a monetary value in terms of the -- number of cents, i.e. $2,000.20 would be expressed as -- Money { cents = 200020 }. newtype Money Money :: 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. -- --
-- >>> import Data.Vector
--
-- >>> :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
-- | Variable-length text type with limit
data VarChar (n :: Nat)
-- | Constructor for VarChar
varChar :: forall n. KnownNat n => Text -> Maybe (VarChar n)
-- | Access the Text of a VarChar
getVarChar :: VarChar n -> Text
-- | Fixed-length, blank padded
data FixChar (n :: Nat)
-- | Constructor for FixChar
fixChar :: forall n. KnownNat n => Text -> Maybe (FixChar n)
-- | Access the Text of a FixChar
getFixChar :: FixChar n -> Text
-- | Only is a 1-tuple type, useful for encoding or decoding a
-- singleton
newtype Only x
Only :: x -> Only x
[fromOnly] :: Only x -> x
instance GHC.Show.Show (Squeal.PostgreSQL.Type.FixChar n)
instance GHC.Read.Read (Squeal.PostgreSQL.Type.FixChar n)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.FixChar n)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.FixChar n)
instance GHC.Show.Show (Squeal.PostgreSQL.Type.VarChar n)
instance GHC.Read.Read (Squeal.PostgreSQL.Type.VarChar n)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.VarChar n)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.VarChar n)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Only x)
instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Type.Only x)
instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Type.Only x)
instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Only x)
instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Only x)
instance Data.Traversable.Traversable Squeal.PostgreSQL.Type.Only
instance Data.Foldable.Foldable Squeal.PostgreSQL.Type.Only
instance GHC.Base.Functor Squeal.PostgreSQL.Type.Only
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.FixArray arr)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.FixArray arr)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.FixArray arr)
instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.Type.FixArray arr)
instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.Type.FixArray arr)
instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.Type.FixArray arr)
instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.Type.FixArray arr)
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.VarArray arr)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.VarArray arr)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.VarArray arr)
instance GHC.Read.Read arr => GHC.Read.Read (Squeal.PostgreSQL.Type.VarArray arr)
instance GHC.Show.Show arr => GHC.Show.Show (Squeal.PostgreSQL.Type.VarArray arr)
instance GHC.Classes.Ord arr => GHC.Classes.Ord (Squeal.PostgreSQL.Type.VarArray arr)
instance GHC.Classes.Eq arr => GHC.Classes.Eq (Squeal.PostgreSQL.Type.VarArray arr)
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Enumerated enum)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Enumerated enum)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Enumerated enum)
instance GHC.Read.Read enum => GHC.Read.Read (Squeal.PostgreSQL.Type.Enumerated enum)
instance GHC.Show.Show enum => GHC.Show.Show (Squeal.PostgreSQL.Type.Enumerated enum)
instance GHC.Classes.Ord enum => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Enumerated enum)
instance GHC.Classes.Eq enum => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Enumerated enum)
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Composite record)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Composite record)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Composite record)
instance GHC.Read.Read record => GHC.Read.Read (Squeal.PostgreSQL.Type.Composite record)
instance GHC.Show.Show record => GHC.Show.Show (Squeal.PostgreSQL.Type.Composite record)
instance GHC.Classes.Ord record => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Composite record)
instance GHC.Classes.Eq record => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Composite record)
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Jsonb hask)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Jsonb hask)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Jsonb hask)
instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.Type.Jsonb hask)
instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.Type.Jsonb hask)
instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Jsonb hask)
instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Jsonb hask)
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Json hask)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Json hask)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Json hask)
instance GHC.Read.Read hask => GHC.Read.Read (Squeal.PostgreSQL.Type.Json hask)
instance GHC.Show.Show hask => GHC.Show.Show (Squeal.PostgreSQL.Type.Json hask)
instance GHC.Classes.Ord hask => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Json hask)
instance GHC.Classes.Eq hask => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Json hask)
instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Type.Money
instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Type.Money
instance GHC.Generics.Generic Squeal.PostgreSQL.Type.Money
instance GHC.Read.Read Squeal.PostgreSQL.Type.Money
instance GHC.Show.Show Squeal.PostgreSQL.Type.Money
instance GHC.Classes.Ord Squeal.PostgreSQL.Type.Money
instance GHC.Classes.Eq Squeal.PostgreSQL.Type.Money
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Type.Only x)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Type.Only x)
-- | Haskell singly-linked lists are very powerful. This module provides
-- functionality for type-level lists, heterogeneous lists and type
-- aligned lists.
module Squeal.PostgreSQL.Type.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 8 *: -- | A list of length one. one :: f x -> NP f '[x] -- | 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) -- | A Path with steps in p is a singly linked list of -- "type-aligned" constructions of p. -- --
-- >>> :{
-- let
-- path :: Path (->) String Int
-- path = length :>> (\x -> x^2) :>> Done
-- in
-- qfold path "hello"
-- :}
-- 25
--
data Path (p :: k -> k -> Type) (x :: k) (y :: k) :: forall k. () => k -> k -> Type -> k -> k -> Type
[Done] :: forall k (p :: k -> k -> Type) (x :: k) (y :: k). () => Path p x x
[:>>] :: forall k (p :: k -> k -> Type) (x :: k) (y :: k) (y1 :: k). () => p x y1 -> Path p y1 y -> Path p x y
infixr 7 :>>
-- | 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 a (expr :: a -> *). Squeal.PostgreSQL.Type.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.Type.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 -- | Map a function over an Aliased expression. mapAliased :: (expr x -> expr y) -> Aliased expr (alias ::: x) -> Aliased expr (alias ::: y) -- | 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 qualifier alias expression
(!) :: IsQualified qualifier alias expression => Alias qualifier -> Alias alias -> expression
infixl 9 !
-- | Grouping is an auxiliary namespace, created by GROUP
-- BY clauses (groupBy), 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.Type.Alias.QualifiedAlias qualifier alias)
instance GHC.Show.Show (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.Alias.QualifiedAlias qualifier alias)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Type.Alias.Alias alias)
instance GHC.Show.Show (Squeal.PostgreSQL.Type.Alias.Alias alias)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Type.Alias.Alias alias)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Type.Alias.Alias alias)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Type.Alias.Alias alias)
instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Show.Show (expression ty) => GHC.Show.Show (Squeal.PostgreSQL.Type.Alias.Aliased expression (alias Squeal.PostgreSQL.Type.Alias.::: ty))
instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Classes.Eq (expression ty) => GHC.Classes.Eq (Squeal.PostgreSQL.Type.Alias.Aliased expression (alias Squeal.PostgreSQL.Type.Alias.::: ty))
instance forall k (expression :: k -> *) (ty :: k) (alias :: GHC.Types.Symbol). GHC.Classes.Ord (expression ty) => GHC.Classes.Ord (Squeal.PostgreSQL.Type.Alias.Aliased expression (alias Squeal.PostgreSQL.Type.Alias.::: ty))
instance (q Data.Type.Equality.~ q', a Data.Type.Equality.~ a') => Squeal.PostgreSQL.Type.Alias.IsQualified q a (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q' a')
instance (q' Data.Type.Equality.~ "public", a Data.Type.Equality.~ a') => GHC.OverloadedLabels.IsLabel a (Squeal.PostgreSQL.Type.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.Type.Alias.IsQualified q0 a0 (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q1) (a1 Squeal.PostgreSQL.Type.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.Type.Alias.Aliased (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q) (a1 Squeal.PostgreSQL.Type.Alias.::: a2))
instance (GHC.TypeLits.KnownSymbol q, GHC.TypeLits.KnownSymbol a) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Type.Alias.QualifiedAlias q a)
instance Squeal.PostgreSQL.Type.Alias.IsQualified qualifier alias (Squeal.PostgreSQL.Type.Alias.Alias qualifier, Squeal.PostgreSQL.Type.Alias.Alias alias)
instance forall kind (fields :: [(GHC.Types.Symbol, kind)]). Squeal.PostgreSQL.Type.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.Type.Alias.Has alias fields field, Squeal.PostgreSQL.Type.Alias.HasAll aliases fields subfields) => Squeal.PostgreSQL.Type.Alias.HasAll (alias : aliases) fields ((alias Squeal.PostgreSQL.Type.Alias.::: field) : subfields)
instance forall k (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, k)]) (field :: k). Squeal.PostgreSQL.Type.Alias.Has alias fields field => Squeal.PostgreSQL.Type.Alias.HasIn fields (alias Squeal.PostgreSQL.Type.Alias.::: field)
instance forall kind (alias :: GHC.Types.Symbol) (field0 :: kind) (field1 :: kind) (fields :: [(GHC.Types.Symbol, kind)]). (GHC.TypeLits.KnownSymbol alias, field0 Data.Type.Equality.~ field1) => Squeal.PostgreSQL.Type.Alias.Has alias ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) field1
instance forall kind (alias :: GHC.Types.Symbol) (fields :: [(GHC.Types.Symbol, kind)]) (field :: kind) (field' :: (GHC.Types.Symbol, kind)). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.Has alias fields field) => Squeal.PostgreSQL.Type.Alias.Has alias (field' : fields) field
instance forall k (alias :: GHC.Types.Symbol) (aliased :: (GHC.Types.Symbol, k)) (ty :: k) (expression :: k -> *). (GHC.TypeLits.KnownSymbol alias, aliased Data.Type.Equality.~ (alias Squeal.PostgreSQL.Type.Alias.::: ty)) => Squeal.PostgreSQL.Type.Alias.Aliasable alias (expression ty) (Squeal.PostgreSQL.Type.Alias.Aliased expression aliased)
instance forall k (alias :: GHC.Types.Symbol) (tys :: [(GHC.Types.Symbol, k)]) (ty :: k) (expression :: k -> *). (GHC.TypeLits.KnownSymbol alias, tys Data.Type.Equality.~ '[alias Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.Aliasable alias (expression ty) (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased expression) tys)
instance (alias0 Data.Type.Equality.~ alias1, alias0 Data.Type.Equality.~ alias2, GHC.TypeLits.KnownSymbol alias2) => GHC.OverloadedLabels.IsLabel alias0 (Squeal.PostgreSQL.Type.Alias.Aliased Squeal.PostgreSQL.Type.Alias.Alias (alias1 Squeal.PostgreSQL.Type.Alias.::: alias2))
instance (alias1 Data.Type.Equality.~ alias2) => GHC.OverloadedLabels.IsLabel alias1 (Squeal.PostgreSQL.Type.Alias.Alias alias2)
instance (aliases Data.Type.Equality.~ '[alias]) => GHC.OverloadedLabels.IsLabel alias (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Alias.Alias aliases)
instance GHC.TypeLits.KnownSymbol alias => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Type.Alias.Alias alias)
instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol aliases => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Alias.Alias aliases)
instance (GHC.TypeLits.KnownSymbol table, GHC.TypeLits.KnownSymbol column) => Squeal.PostgreSQL.Type.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.Type.Alias.GroupedBy table column bys) => Squeal.PostgreSQL.Type.Alias.GroupedBy table column (tabcol : bys)
-- | Schema provides a type-level DSL for kinds of Postgres types,
-- tables, schema, constraints, and more. It also defines useful type
-- families to operate on these.
module Squeal.PostgreSQL.Type.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 :: NullType -> PGType -- | fixed length array PGfixarray :: [Nat] -> NullType -> 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 PGoid :: PGType -- | Range types are data types representing a range of values of some -- element type (called the range's subtype). PGrange :: PGType -> PGType -- | an escape hatch for unsupported PostgreSQL types UnsafePGType :: Symbol -> PGType -- | NullType encodes the potential presence or definite absence of -- a NULL allowing operations which are sensitive to such to be -- well typed. -- --
-- >>> :kind 'Null 'PGint4
-- 'Null 'PGint4 :: NullType
--
-- >>> :kind 'NotNull ('PGvarchar 50)
-- 'NotNull ('PGvarchar 50) :: NullType
--
data NullType
-- | NULL may be present
Null :: PGType -> NullType
-- | NULL is absent
NotNull :: PGType -> NullType
-- | A RowType is a row of NullType. 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, NullType)]
-- | 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 = (Optionality, NullType) -- | 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
Index :: IndexType -> SchemumType
Function :: FunctionType -> SchemumType
UnsafeSchemum :: Symbol -> SchemumType
-- | PostgreSQL provides several index types: B-tree, Hash, GiST, SP-GiST,
-- GIN and BRIN. Each index type uses a different algorithm that is best
-- suited to different types of queries.
data IndexType
-- | B-trees can handle equality and range queries on data that can be
-- sorted into some ordering.
Btree :: IndexType
-- | Hash indexes can only handle simple equality comparisons.
Hash :: IndexType
-- | GiST indexes are not a single kind of index, but rather an
-- infrastructure within which many different indexing strategies can be
-- implemented.
Gist :: IndexType
-- | SP-GiST indexes, like GiST indexes, offer an infrastructure that
-- supports various kinds of searches.
Spgist :: IndexType
-- | GIN indexes are “inverted indexes” which are appropriate for data
-- values that contain multiple component values, such as arrays.
Gin :: IndexType
-- | BRIN indexes (a shorthand for Block Range INdexes) store summaries
-- about the values stored in consecutive physical block ranges of a
-- table.
Brin :: IndexType
-- | Use :=> to pair the parameter types with the return type of
-- a function.
type FunctionType = ([NullType], ReturnsType)
-- | Return type of a function
data ReturnsType
-- | function
Returns :: NullType -> ReturnsType
-- | set returning function
ReturnsTable :: RowType -> ReturnsType
-- | 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
-- | Similar to Create but no error on pre-existence
type family CreateIfNotExists alias x xs
-- | Similar to Create but used to replace values with the same
-- type.
type family CreateOrReplace 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
-- | Drop a particular flavor of schemum type
type family DropSchemum alias sch xs
-- | Similar to Drop but no error on non-existence
type family DropIfExists alias xs
-- | Similar to DropSchemum but no error on non-existence
type family DropSchemumIfExists alias sch xs
-- | Alter alias x xs replaces the type associated with an
-- alias in xs with the type x and is used in
-- alterTable and alterColumn.
type family Alter alias x xs
-- | Similar to Alter but no error on non-existence
type family AlterIfExists 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
-- | Similar to Rename but no error on non-existence
type family RenameIfExists 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
-- | 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 :: NullType) :: 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 NullType.
type family NullifyType (ty :: NullType) :: NullType
-- | 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
-- | Updatable lists of columns
type Updatable table columns = (All (HasIn (TableToColumns table)) columns, AllUnique columns, SListI (TableToColumns table))
-- | No elem of xs appears more than once, in the context of
-- assignment.
class AllUnique (xs :: [(Symbol, a)])
-- | Utility class for AllUnique to provide nicer error messages.
class IsNotElem x isElem
-- | Calculate the schema and name of a user defined type.
type family UserType (db :: SchemasType) (ty :: PGType)
-- | Calculate the name of a user defined type.
type family UserTypeName (schema :: SchemaType) (ty :: PGType)
-- | Helper to calculate the schema of a user defined type.
type family UserTypeNamespace (sch :: Symbol) (td :: Maybe Symbol) (schemas :: SchemasType) (ty :: PGType)
instance Squeal.PostgreSQL.Type.Schema.AllUnique '[]
instance forall a (x :: (GHC.Types.Symbol, a)) (xs :: [(GHC.Types.Symbol, a)]). (Squeal.PostgreSQL.Type.Schema.IsNotElem x (Squeal.PostgreSQL.Type.List.Elem x xs), Squeal.PostgreSQL.Type.Schema.AllUnique xs) => Squeal.PostgreSQL.Type.Schema.AllUnique (x : xs)
instance forall k (x :: k). Squeal.PostgreSQL.Type.Schema.IsNotElem x 'GHC.Types.False
instance forall k1 k2 (alias :: k2) (a :: k1). (TypeError ...) => Squeal.PostgreSQL.Type.Schema.IsNotElem '(alias, a) 'GHC.Types.True
instance (label Data.Type.Equality.~ label1) => Squeal.PostgreSQL.Type.Schema.IsPGlabel label (Squeal.PostgreSQL.Type.Schema.PGlabel label1)
instance (labels Data.Type.Equality.~ '[label]) => Squeal.PostgreSQL.Type.Schema.IsPGlabel label (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Schema.PGlabel labels)
instance GHC.TypeLits.KnownSymbol label => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Type.Schema.PGlabel label)
instance Data.SOP.Constraint.All GHC.TypeLits.KnownSymbol labels => Squeal.PostgreSQL.Render.RenderSQL (Data.SOP.NP.NP Squeal.PostgreSQL.Type.Schema.PGlabel labels)
instance forall k (ty0 :: k) (ty1 :: k) (alias0 :: GHC.Types.Symbol) (def0 :: Squeal.PostgreSQL.Type.Schema.Optionality) (null0 :: k -> Squeal.PostgreSQL.Type.Schema.NullType) (alias1 :: GHC.Types.Symbol) (def1 :: Squeal.PostgreSQL.Type.Schema.Optionality) (null1 :: k -> Squeal.PostgreSQL.Type.Schema.NullType). (ty0 Data.Type.Equality.~ ty1) => Squeal.PostgreSQL.Type.Schema.SamePGType (alias0 Squeal.PostgreSQL.Type.Alias.::: (def0 Squeal.PostgreSQL.Type.Schema.:=> null0 ty0)) (alias1 Squeal.PostgreSQL.Type.Alias.::: (def1 Squeal.PostgreSQL.Type.Schema.:=> null1 ty1))
-- | PG provides type families for turning Haskell Types into
-- corresponding Postgres types.
module Squeal.PostgreSQL.Type.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 ---- -- The preferred way to generate PGs of your own type is through -- generalized newtype deriving or via deriving. -- --
-- >>> newtype UserId = UserId {getUserId :: UUID} deriving newtype IsPG
--
--
-- -- >>> :kind! PG UserId -- PG UserId :: PGType -- = 'PGuuid ---- --
-- >>> :{
-- data Answer = Yes | No
-- deriving stock GHC.Generic
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- deriving IsPG via Enumerated Answer
-- :}
--
--
-- -- >>> :kind! PG Answer -- PG Answer :: PGType -- = 'PGenum '["Yes", "No"] ---- --
-- >>> :{
-- data Complex = Complex {real :: Double, imaginary :: Double}
-- deriving stock GHC.Generic
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- deriving IsPG via Composite Complex
-- :}
--
--
-- -- >>> :kind! PG Complex -- PG Complex :: PGType -- = 'PGcomposite -- '["real" ::: 'NotNull 'PGfloat8, -- "imaginary" ::: 'NotNull 'PGfloat8] --class IsPG (hask :: Type) where { type family PG hask :: PGType; } -- | NullPG turns a Haskell type into a NullType. -- --
-- >>> :kind! NullPG Double -- NullPG Double :: NullType -- = 'NotNull 'PGfloat8 -- -- >>> :kind! NullPG (Maybe Double) -- NullPG (Maybe Double) :: NullType -- = 'Null 'PGfloat8 --type family NullPG (hask :: Type) :: NullType -- | TuplePG turns a Haskell tuple type (including record types) -- into the corresponding list of NullTypes. -- --
-- >>> :kind! TuplePG (Double, Maybe Char)
-- TuplePG (Double, Maybe Char) :: [NullType]
-- = '[ 'NotNull 'PGfloat8, 'Null ('PGchar 1)]
--
type family TuplePG (hask :: Type) :: [NullType]
-- | 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, NullType)]
-- = '["name" ::: 'NotNull 'PGtext, "age" ::: 'NotNull 'PGint4]
--
type family RowPG (hask :: Type) :: RowType
-- | 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, up to a depth of 10 for each dimension. type family DimPG (hask :: Type) :: [Nat] -- | FixPG extracts NullPG of the base type of nested -- homogeneous tuples, up to a depth of 10 for each dimension. type family FixPG (hask :: Type) :: NullType -- | TupleOf turns a list of Haskell Types into a list of -- NullTypes. type family TupleOf (tuple :: [Type]) :: [NullType] -- | 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 Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.FixArray hask) instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Enumerated hask) instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Composite hask) instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector x)) instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.VarArray [x]) instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Bool instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Int.Int16 instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Int.Int32 instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Int.Int64 instance Squeal.PostgreSQL.Type.PG.IsPG Database.PostgreSQL.LibPQ.Oid instance Squeal.PostgreSQL.Type.PG.IsPG Data.Scientific.Scientific instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Float instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Double instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Types.Char instance Squeal.PostgreSQL.Type.PG.IsPG Data.Text.Internal.Text instance Squeal.PostgreSQL.Type.PG.IsPG Data.Text.Internal.Lazy.Text instance Squeal.PostgreSQL.Type.PG.IsPG GHC.Base.String instance Squeal.PostgreSQL.Type.PG.IsPG Data.ByteString.Internal.ByteString instance Squeal.PostgreSQL.Type.PG.IsPG Data.ByteString.Lazy.Internal.ByteString instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.LocalTime.Internal.LocalTime.LocalTime instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.Clock.Internal.UTCTime.UTCTime instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.Calendar.Days.Day instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay instance Squeal.PostgreSQL.Type.PG.IsPG (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone) instance Squeal.PostgreSQL.Type.PG.IsPG Data.Time.Clock.Internal.DiffTime.DiffTime instance Squeal.PostgreSQL.Type.PG.IsPG Data.UUID.Types.Internal.UUID instance Squeal.PostgreSQL.Type.PG.IsPG (Network.IP.Addr.NetAddr Network.IP.Addr.IP) instance Squeal.PostgreSQL.Type.PG.IsPG Data.Aeson.Types.Internal.Value instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.VarChar n) instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.FixChar n) instance Squeal.PostgreSQL.Type.PG.IsPG Squeal.PostgreSQL.Type.Money instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Json hask) instance Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Type.Jsonb hask) -- | Object identifiers are used internally by PostgreSQL as primary keys. -- They are needed to correctly encode statement parameters. module Squeal.PostgreSQL.Session.Oid data Oid -- | The Oid of a PGType -- --
-- >>> :set -XTypeApplications -- -- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb" -- -- >>> runReaderT (oidOf @'[] @'PGbool) conn -- Oid 16 ---- --
-- >>> finish conn --class OidOf (db :: SchemasType) (pg :: PGType) oidOf :: OidOf db pg => ReaderT (K Connection db) IO Oid -- | The Oid of an array class OidOfArray (db :: SchemasType) (pg :: PGType) oidOfArray :: OidOfArray db pg => ReaderT (K Connection db) IO Oid -- | The Oid of a NullType class OidOfNull (db :: SchemasType) (ty :: NullType) oidOfNull :: OidOfNull db ty => ReaderT (K Connection db) IO Oid -- | The Oid of a field class OidOfField (db :: SchemasType) (field :: (Symbol, NullType)) oidOfField :: OidOfField db field => ReaderT (K Connection db) IO Oid instance Squeal.PostgreSQL.Session.Oid.OidOfNull db ty => Squeal.PostgreSQL.Session.Oid.OidOfField db (fld Squeal.PostgreSQL.Type.Alias.::: ty) instance Squeal.PostgreSQL.Session.Oid.OidOf db pg => Squeal.PostgreSQL.Session.Oid.OidOfNull db (null pg) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db pg => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGvararray (null pg)) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db pg => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGfixarray dims (null pg)) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGbool instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGint2 instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGint4 instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGint8 instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGnumeric instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGfloat4 instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGfloat8 instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGmoney instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGchar n) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGvarchar n) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtext instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGbytea instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtimestamp instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGdate instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtime instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtimetz instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGuuid instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGinet instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGjson instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGjsonb instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtsvector instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGtsquery instance Squeal.PostgreSQL.Session.Oid.OidOfArray db 'Squeal.PostgreSQL.Type.Schema.PGoid instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint4) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint8) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGnumeric) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamp) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz) instance Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGdate) instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGcomposite row))) => Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) => Squeal.PostgreSQL.Session.Oid.OidOfArray db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGbool instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGint2 instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGint4 instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGint8 instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGnumeric instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGfloat4 instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGfloat8 instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGmoney instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGchar n) instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGvarchar n) instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtext instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGbytea instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtimestamp instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGdate instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtime instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtimetz instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGuuid instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGinet instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGjson instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGjsonb instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtsvector instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGtsquery instance Squeal.PostgreSQL.Session.Oid.OidOf db 'Squeal.PostgreSQL.Type.Schema.PGoid instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint4) instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint8) instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGnumeric) instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamp) instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz) instance Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGdate) instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGcomposite row))) => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) => Squeal.PostgreSQL.Session.Oid.OidOf db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) -- | database connections module Squeal.PostgreSQL.Session.Connection -- | 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 DB = '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint2])]]
--
-- >>> :set -XTypeApplications
--
-- >>> :set -XOverloadedStrings
--
-- >>> conn <- connectdb @DB "host=localhost port=5432 dbname=exampledb"
--
--
-- Note that, for now, squeal doesn't offer any protection from
-- connecting with the wrong schema!
connectdb :: forall (db :: SchemasType) io. MonadIO io => ByteString -> io (K Connection db)
-- | Closes the connection to the server.
finish :: MonadIO io => K Connection db -> io ()
-- | Safely lowerConnection to a smaller schema.
lowerConnection :: K Connection (schema : db) -> K Connection db
-- | 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
-- | structured query language
module Squeal.PostgreSQL.Query
-- | The top level Query_ type is parameterized by a db
-- SchemasType, against which the query is type-checked, an input
-- params Haskell Type, and an ouput row Haskell
-- Type.
--
-- Query_ is a type family which resolves into a Query, so
-- don't be fooled by the input params and output row Haskell
-- Types, which are converted into appropriate Postgres
-- [NullType] params and RowType rows.
-- Use a top-level Statement to fix actual Haskell input params
-- and output rows.
--
-- A top-level Query_ can be run using runQueryParams, or
-- if params = () using runQuery.
--
-- Generally, params 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 :: int4)))
--
--
-- 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 :: int8)) AS "col1", "col1" AS "col2" FROM "tab" AS "table1" GROUP BY "col1" HAVING (sum(DISTINCT "col2") > (1 :: int8))
--
--
-- 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")
--
--
--
-- >>> :{
-- let
-- query :: Query_ (Public OrdersSchema) () Order
-- query = select_
-- ( #o ! #price `as` #price :*
-- #c ! #name `as` #customerName :*
-- #s ! #name `as` #shipperName )
-- ( from (table (#orders `as` #o)
-- & (inner.JoinLateral) (select Star (from (table #customers)) `as` #c)
-- (#o ! #customer_id .== #c ! #id)
-- & (inner.JoinLateral) (select Star (from (table #shippers)) `as` #s)
-- (#o ! #shipper_id .== #s ! #id)) )
-- in printSQL query
-- :}
-- SELECT "o"."price" AS "price", "c"."name" AS "customerName", "s"."name" AS "shipperName" FROM "orders" AS "o" INNER JOIN LATERAL (SELECT * FROM "customers" AS "customers") AS "c" ON ("o"."customer_id" = "c"."id") INNER JOIN LATERAL (SELECT * FROM "shippers" AS "shippers") AS "s" ON ("o"."shipper_id" = "s"."id")
--
--
-- self-join:
--
--
-- >>> :{
-- 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_ db () (Row String Bool)
-- query = values
-- ("true" `as` #col1 :* true `as` #col2)
-- ["false" `as` #col1 :* false `as` #col2]
-- in printSQL query
-- :}
-- SELECT * FROM (VALUES ((E'true' :: text), TRUE), ((E'false' :: text), 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_ (db :: SchemasType) (params :: 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
--
--
-- >>> import Data.Monoid (Sum (..))
--
-- >>> import Data.Int (Int64)
--
-- >>> :{
-- let
-- query :: Query_ schema () (Sum Int64)
-- query = withRecursive
-- ( values_ ((1 & astype int) `as` #n)
-- `unionAll`
-- select_ ((#n + 1) `as` #n)
-- (from (common #t) & where_ (#n .< 100)) `as` #t )
-- ( select_ (fromNull 0 (sum_ (All #n)) `as` #getSum) (from (common #t) & groupBy Nil))
-- in printSQL query
-- :}
-- WITH RECURSIVE "t" AS ((SELECT * FROM (VALUES (((1 :: int4) :: int))) AS t ("n")) UNION ALL (SELECT ("n" + (1 :: int4)) AS "n" FROM "t" AS "t" WHERE ("n" < (100 :: int4)))) SELECT COALESCE(sum(ALL "n"), (0 :: int8)) AS "getSum" FROM "t" AS "t"
--
withRecursive :: Aliased (Query lat (recursive : with) db params) recursive -> Query lat (recursive : with) db params row -> Query lat with db params row
instance Squeal.PostgreSQL.Query.With.With (Squeal.PostgreSQL.Query.Query lat)
instance (GHC.TypeLits.KnownSymbol cte, with1 Data.Type.Equality.~ ((cte Squeal.PostgreSQL.Type.Alias.::: common) : with)) => Squeal.PostgreSQL.Type.Alias.Aliasable cte (statement with db params common) (Squeal.PostgreSQL.Query.With.CommonTableExpression statement db params with with1)
instance (GHC.TypeLits.KnownSymbol cte, with1 Data.Type.Equality.~ ((cte Squeal.PostgreSQL.Type.Alias.::: common) : with)) => Squeal.PostgreSQL.Type.Alias.Aliasable cte (statement with db params common) (Control.Category.Free.Path (Squeal.PostgreSQL.Query.With.CommonTableExpression statement db params) with with1)
instance (forall (c :: Squeal.PostgreSQL.Type.Schema.FromType) (s :: Squeal.PostgreSQL.Type.Schema.SchemasType) (p :: [Squeal.PostgreSQL.Type.Schema.NullType]) (r :: Squeal.PostgreSQL.Type.Schema.RowType). Squeal.PostgreSQL.Render.RenderSQL (statement c s p r)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.With.CommonTableExpression statement db params with0 with1)
-- | from clauses
module Squeal.PostgreSQL.Query.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 (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
UnsafeFromClause :: ByteString -> FromClause
[renderFromClause] :: FromClause -> ByteString
-- | A real table is a table from the database.
table :: (Has sch db schema, Has tab schema ( 'Table table)) => Aliased (QualifiedAlias sch) (alias ::: tab) -> FromClause lat with db params '[alias ::: TableToRow table]
-- | subquery derives a table from a Query.
subquery :: Aliased (Query lat with db params) query -> FromClause lat with db params '[query]
-- | view derives a table from a View.
view :: (Has sch db schema, Has vw schema ( 'View view)) => Aliased (QualifiedAlias sch) (alias ::: vw) -> FromClause lat with db params '[alias ::: view]
-- | common derives a table from a common table expression.
common :: Has cte with common => Aliased Alias (alias ::: cte) -> FromClause lat with db params '[alias ::: common]
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
instance GHC.Show.Show (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.From.FromClause lat with db params from)
instance Squeal.PostgreSQL.Type.List.Additional (Squeal.PostgreSQL.Query.From.FromClause lat with db params)
-- | optional expressions
module Squeal.PostgreSQL.Expression.Default
-- | Optional is either Default or Setting of a value,
-- parameterized by an appropriate Optionality.
data Optional (expr :: k -> Type) (ty :: (Optionality, k))
-- | Use the Default value for a column.
[Default] :: Optional expr ( 'Def :=> ty)
-- | Set a value for a column.
[Set] :: expr ty -> Optional expr (def :=> ty)
-- | Map a function over an Optional expression.
mapOptional :: (expr x -> expr y) -> Optional expr (def :=> x) -> Optional expr (def :=> y)
-- | NotDefault pattern analagous to Just.
pattern NotDefault :: ty -> Optional I ( 'Def :=> ty)
instance forall k (expr :: k -> *) (ty :: (Squeal.PostgreSQL.Type.Schema.Optionality, k)). (forall (x :: k). Squeal.PostgreSQL.Render.RenderSQL (expr x)) => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Default.Optional expr ty)
-- | 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 insertInto 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 -- | Call a user defined function of a single variable -- --
-- >>> type Fn = '[ 'Null 'PGint4] :=> 'Returns ('NotNull 'PGnumeric)
--
-- >>> type Schema = '["fn" ::: 'Function Fn]
--
-- >>> :{
-- let
-- fn :: Fun (Public Schema) ('Null 'PGint4) ('NotNull 'PGnumeric)
-- fn = function #fn
-- in
-- printSQL (fn 1)
-- :}
-- "fn"((1 :: int4))
--
function :: (Has sch db schema, Has fun schema ( 'Function ('[x] :=> 'Returns y))) => QualifiedAlias sch fun -> Fun db x y
-- | -- >>> printSQL $ unsafeLeftOp "NOT" true -- (NOT TRUE) --unsafeLeftOp :: ByteString -> x --> y -- |
-- >>> printSQL $ true & unsafeRightOp "IS NOT TRUE" -- (TRUE IS NOT TRUE) --unsafeRightOp :: ByteString -> x --> y -- | A RankNType for binary operators. type Operator x1 x2 y = forall grp lat with db params from. Expression grp lat with db params from x1 " left input" -> Expression grp lat with db params from x2 " right input" -> Expression grp lat with db params from y " output" -- | Like Operator but depends on the schemas of the database type OperatorDB db x1 x2 y = forall grp lat with params from. Expression grp lat with db params from x1 " left input" -> Expression grp lat with db params from x2 " right input" -> Expression grp lat with db params from y " output" -- |
-- >>> printSQL $ unsafeBinaryOp "OR" true false -- (TRUE OR FALSE) --unsafeBinaryOp :: ByteString -> Operator ty0 ty1 ty2 -- | Contained by operators class PGSubset ty (@>) :: PGSubset ty => Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) (<@) :: PGSubset ty => Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) -- | Intersection operator class PGIntersect ty (@&&) :: PGIntersect ty => Operator (null0 ty) (null1 ty) ( 'Null 'PGbool) -- | A RankNType for functions with a variable-length list of -- homogeneous arguments and at least 1 more argument. type FunctionVar x0 x1 y = forall grp lat with db params from. [Expression grp lat with db params from x0] " inputs" -> Expression grp lat with db params from x1 " must have at least 1 input" -> Expression grp lat with db params from y " output" -- |
-- >>> 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 (--->) xs y = forall db. FunN db xs y -- | Like ---> but depends on the schemas of the database type FunN db xs y = forall grp lat with params from. NP (Expression grp lat with db params from) xs " inputs" -> Expression grp lat with db params from y " output" -- |
-- >>> printSQL $ unsafeFunctionN "f" (currentTime :* localTimestamp :* false *: inline 'a') -- f(CURRENT_TIME, LOCALTIMESTAMP, FALSE, (E'a' :: char(1))) --unsafeFunctionN :: SListI xs => ByteString -> xs ---> y -- | Call a user defined multivariable function -- --
-- >>> type Fn = '[ 'Null 'PGint4, 'Null 'PGbool] :=> 'Returns ('NotNull 'PGnumeric)
--
-- >>> type Schema = '["fn" ::: 'Function Fn]
--
-- >>> :{
-- let
-- fn :: FunN (Public Schema) '[ 'Null 'PGint4, 'Null 'PGbool] ('NotNull 'PGnumeric)
-- fn = functionN #fn
-- in
-- printSQL (fn (1 *: true))
-- :}
-- "fn"((1 :: int4), TRUE)
--
functionN :: (Has sch db schema, Has fun schema ( 'Function (xs :=> 'Returns y)), SListI xs) => QualifiedAlias sch fun -> FunN db xs y
-- | & 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 & instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) instance Squeal.PostgreSQL.Expression.PGIntersect ('Squeal.PostgreSQL.Type.Schema.PGvararray ty) instance Squeal.PostgreSQL.Expression.PGIntersect ('Squeal.PostgreSQL.Type.Schema.PGrange ty) instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Type.Schema.PGjsonb instance Squeal.PostgreSQL.Expression.PGSubset 'Squeal.PostgreSQL.Type.Schema.PGtsquery instance Squeal.PostgreSQL.Expression.PGSubset ('Squeal.PostgreSQL.Type.Schema.PGvararray ty) instance Squeal.PostgreSQL.Expression.PGSubset ('Squeal.PostgreSQL.Type.Schema.PGrange ty) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from ty) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, tys Data.Type.Equality.~ '[ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) tys) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) column) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from)) columns) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from ty) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, tys Data.Type.Equality.~ '[ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) tys) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from) column) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from)) columns) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from ty) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, tys Data.Type.Equality.~ '[ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) tys) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) column) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from)) columns) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from ty) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, tys Data.Type.Equality.~ '[ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) tys) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, column Data.Type.Equality.~ (col Squeal.PostgreSQL.Type.Alias.::: ty)) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from) column) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row, Squeal.PostgreSQL.Type.Alias.Has col row ty, Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys, columns Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Data.SOP.NP.NP (Squeal.PostgreSQL.Type.Alias.Aliased (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from)) columns) instance (GHC.TypeLits.KnownSymbol label, Squeal.PostgreSQL.Type.List.In label labels) => Squeal.PostgreSQL.Type.Schema.IsPGlabel label (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGint2)) instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGint4)) instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGint8)) instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat4)) instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat8)) instance GHC.Num.Num (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGnumeric)) instance GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat4)) instance GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat8)) instance GHC.Real.Fractional (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGnumeric)) instance GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat4)) instance GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGfloat8)) instance GHC.Float.Floating (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGnumeric)) instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtext)) instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsvector)) instance Data.String.IsString (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsquery)) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null ('Squeal.PostgreSQL.Type.Schema.PGvararray ty))) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGjsonb)) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtext)) instance GHC.Base.Semigroup (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsvector)) instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtext)) instance GHC.Base.Monoid (Squeal.PostgreSQL.Expression.Expression grp lat with db params from (null 'Squeal.PostgreSQL.Type.Schema.PGtsvector)) -- | values statements module Squeal.PostgreSQL.Query.Values -- | values computes a row value or set of row values specified by -- value expressions. It is most commonly used to generate a “constant -- table” within a larger command, but it can be used on its own. -- --
-- >>> type Row = '["a" ::: 'NotNull 'PGint4, "b" ::: 'NotNull 'PGtext]
--
-- >>> let query = values (1 `as` #a :* "one" `as` #b) [] :: Query lat with db '[] Row
--
-- >>> printSQL query
-- SELECT * FROM (VALUES ((1 :: int4), (E'one' :: text))) AS t ("a", "b")
--
values :: SListI cols => NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols -> [NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols] -> Query lat with db params cols
-- | values_ computes a row value or set of row values specified by
-- value expressions.
values_ :: SListI cols => NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols -> Query lat with db params cols
-- | set returning functions
module Squeal.PostgreSQL.Query.From.Set
-- | A RankNType for set returning functions with 1 argument.
type (-|->) arg set = forall db. SetFun db arg set
-- | A RankNType for set returning functions with multiple
-- argument.
type (--|->) arg set = forall db. SetFunN db arg set " output"
-- | Like -|-> but depends on the schemas of the database
type SetFun db arg row = forall lat with params. Expression 'Ungrouped lat with db params '[] arg " input" -> FromClause lat with db params '[row] " output"
-- | Like --|-> but depends on the schemas of the database
type SetFunN db args set = forall lat with params. NP (Expression 'Ungrouped lat with db params '[]) args " input" -> FromClause lat with db params '[set] " output"
-- | -- generateSeries (start :* stop) ---- -- Generate a series of values, from start to stop with -- a step size of one -- --
-- >>> printSQL (generateSeries @'PGint4 (1 *: 10)) -- generate_series((1 :: int4), (10 :: int4)) --generateSeries :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric] => '[null ty, null ty] --|-> ("generate_series" ::: '["generate_series" ::: null ty]) -- |
-- generateSeriesStep (start :* stop *: step) ---- -- Generate a series of values, from start to stop with -- a step size of step -- --
-- >>> printSQL (generateSeriesStep @'PGint8 (2 :* 100 *: 2)) -- generate_series((2 :: int8), (100 :: int8), (2 :: int8)) --generateSeriesStep :: ty `In` '[ 'PGint4, 'PGint8, 'PGnumeric] => '[null ty, null ty, null ty] --|-> ("generate_series" ::: '["generate_series" ::: null ty]) -- |
-- generateSeriesTimestamp (start :* stop *: step) ---- -- Generate a series of timestamps, from start to stop -- with a step size of step -- --
-- >>> :{
-- let
-- start = now
-- stop = now !+ interval_ 10 Years
-- step = interval_ 1 Months
-- in printSQL (generateSeriesTimestamp (start :* stop *: step))
-- :}
-- generate_series(now(), (now() + (INTERVAL '10.000 years')), (INTERVAL '1.000 months'))
--
generateSeriesTimestamp :: ty `In` '[ 'PGtimestamp, 'PGtimestamptz] => '[null ty, null ty, null 'PGinterval] --|-> ("generate_series" ::: '["generate_series" ::: null ty])
-- | Escape hatch for a set returning function of a single variable
unsafeSetFunction :: forall fun ty row. KnownSymbol fun => ByteString -> ty -|-> (fun ::: row)
-- | Call a user defined set returning function of a single variable
--
--
-- >>> type Fn = '[ 'Null 'PGbool] :=> 'ReturnsTable '["ret" ::: 'NotNull 'PGnumeric]
--
-- >>> type Schema = '["fn" ::: 'Function Fn]
--
-- >>> :{
-- let
-- fn :: SetFun (Public Schema) ('Null 'PGbool) ("fn" ::: '["ret" ::: 'NotNull 'PGnumeric])
-- fn = setFunction #fn
-- in
-- printSQL (fn true)
-- :}
-- "fn"(TRUE)
--
setFunction :: (Has sch db schema, Has fun schema ( 'Function ('[ty] :=> 'ReturnsTable row))) => QualifiedAlias sch fun -> SetFun db ty (fun ::: row)
-- | Escape hatch for a multivariable set returning function
unsafeSetFunctionN :: forall fun tys row. (SListI tys, KnownSymbol fun) => ByteString -> tys --|-> (fun ::: row)
-- | Call a user defined multivariable set returning function
--
--
-- >>> type Fn = '[ 'Null 'PGbool, 'Null 'PGtext] :=> 'ReturnsTable '["ret" ::: 'NotNull 'PGnumeric]
--
-- >>> type Schema = '["fn" ::: 'Function Fn]
--
-- >>> :{
-- let
-- fn :: SetFunN (Public Schema)
-- '[ 'Null 'PGbool, 'Null 'PGtext]
-- ("fn" ::: '["ret" ::: 'NotNull 'PGnumeric])
-- fn = setFunctionN #fn
-- in
-- printSQL (fn (true *: "hi"))
-- :}
-- "fn"(TRUE, (E'hi' :: text))
--
setFunctionN :: (Has sch db schema, Has fun schema ( 'Function (tys :=> 'ReturnsTable row)), SListI tys) => QualifiedAlias sch fun -> SetFunN db tys (fun ::: row)
-- | type expressions
module Squeal.PostgreSQL.Expression.Type
-- | -- >>> printSQL $ true & cast int4 -- (TRUE :: int4) --cast :: TypeExpression db ty1 -> Expression grp lat with db params from ty0 -> Expression grp lat with db params from ty1 -- | A safe version of cast which just matches a value with its -- type. -- --
-- >>> printSQL (1 & astype int) -- ((1 :: int4) :: int) --astype :: TypeExpression db ty -> Expression grp lat with db params from ty -> Expression grp lat with db 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 :: NullTyped db ty => Expression lat common grp db params from ty -> Expression lat common grp db params from ty -- | TypeExpressions are used in casts and createTable -- commands. newtype TypeExpression (db :: SchemasType) (ty :: NullType) UnsafeTypeExpression :: ByteString -> TypeExpression [renderTypeExpression] :: TypeExpression -> ByteString -- | The enum or composite type in a Typedef can be expressed by its -- alias. typedef :: (Has sch db schema, Has td schema ( 'Typedef ty)) => QualifiedAlias sch td -> TypeExpression db (null ty) -- | The composite type corresponding to a Table definition can be -- expressed by its alias. typetable :: (Has sch db schema, Has tab schema ( 'Table table)) => QualifiedAlias sch tab -> TypeExpression db (null ( 'PGcomposite (TableToRow table))) -- | The composite type corresponding to a View definition can be -- expressed by its alias. typeview :: (Has sch db schema, Has vw schema ( 'View view)) => QualifiedAlias sch vw -> TypeExpression db (null ( 'PGcomposite view)) -- | logical Boolean (true/false) bool :: TypeExpression db (null 'PGbool) -- | signed two-byte integer int2 :: TypeExpression db (null 'PGint2) -- | signed two-byte integer smallint :: TypeExpression db (null 'PGint2) -- | signed four-byte integer int4 :: TypeExpression db (null 'PGint4) -- | signed four-byte integer int :: TypeExpression db (null 'PGint4) -- | signed four-byte integer integer :: TypeExpression db (null 'PGint4) -- | signed eight-byte integer int8 :: TypeExpression db (null 'PGint8) -- | signed eight-byte integer bigint :: TypeExpression db (null 'PGint8) -- | arbitrary precision numeric type numeric :: TypeExpression db (null 'PGnumeric) -- | single precision floating-point number (4 bytes) float4 :: TypeExpression db (null 'PGfloat4) -- | single precision floating-point number (4 bytes) real :: TypeExpression db (null 'PGfloat4) -- | double precision floating-point number (8 bytes) float8 :: TypeExpression db (null 'PGfloat8) -- | double precision floating-point number (8 bytes) doublePrecision :: TypeExpression db (null 'PGfloat8) -- | currency amount money :: TypeExpression schema (null 'PGmoney) -- | variable-length character string text :: TypeExpression db (null 'PGtext) -- | fixed-length character string char :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGchar n)) -- | fixed-length character string character :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGchar n)) -- | variable-length character string varchar :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGvarchar n)) -- | variable-length character string characterVarying :: forall n db null. (KnownNat n, 1 <= n) => TypeExpression db (null ( 'PGvarchar n)) -- | binary data ("byte array") bytea :: TypeExpression db (null 'PGbytea) -- | date and time (no time zone) timestamp :: TypeExpression db (null 'PGtimestamp) -- | date and time, including time zone timestampWithTimeZone :: TypeExpression db (null 'PGtimestamptz) -- | date and time, including time zone timestamptz :: TypeExpression db (null 'PGtimestamptz) -- | calendar date (year, month, day) date :: TypeExpression db (null 'PGdate) -- | time of day (no time zone) time :: TypeExpression db (null 'PGtime) -- | time of day, including time zone timeWithTimeZone :: TypeExpression db (null 'PGtimetz) -- | time of day, including time zone timetz :: TypeExpression db (null 'PGtimetz) -- | time span interval :: TypeExpression db (null 'PGinterval) -- | universally unique identifier uuid :: TypeExpression db (null 'PGuuid) -- | IPv4 or IPv6 host address inet :: TypeExpression db (null 'PGinet) -- | textual JSON data json :: TypeExpression db (null 'PGjson) -- | binary JSON data, decomposed jsonb :: TypeExpression db (null 'PGjsonb) -- | variable length array vararray :: TypeExpression db pg -> TypeExpression db (null ( 'PGvararray pg)) -- | fixed length array -- --
-- >>> renderSQL (fixarray @'[2] json) -- "json[2]" --fixarray :: forall dims db null pg. All KnownNat dims => TypeExpression db pg -> TypeExpression db (null ( 'PGfixarray dims pg)) -- | text search query tsvector :: TypeExpression db (null 'PGtsvector) -- | text search document tsquery :: TypeExpression db (null 'PGtsquery) -- | Object identifiers (OIDs) are used internally by PostgreSQL as primary -- keys for various system tables. oid :: TypeExpression db (null 'PGoid) -- | Range of integer int4range :: TypeExpression db (null ( 'PGrange 'PGint4)) -- | Range of bigint int8range :: TypeExpression db (null ( 'PGrange 'PGint8)) -- | Range of numeric numrange :: TypeExpression db (null ( 'PGrange 'PGnumeric)) -- | Range of timestamp without time zone tsrange :: TypeExpression db (null ( 'PGrange 'PGtimestamp)) -- | Range of timestamp with time zone tstzrange :: TypeExpression db (null ( 'PGrange 'PGtimestamptz)) -- | Range of date daterange :: TypeExpression db (null ( 'PGrange 'PGdate)) -- | Anonymous composite record record :: TypeExpression db (null ( 'PGcomposite record)) -- | ColumnTypeExpressions are used in createTable commands. newtype ColumnTypeExpression (db :: 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 db (null ty) -> ColumnTypeExpression db ( 'NoDef :=> 'Null ty) -- | used in createTable commands as a column constraint to ensure -- NULL is not present in a column notNullable :: TypeExpression db (null ty) -> ColumnTypeExpression db ( 'NoDef :=> 'NotNull ty) -- | used in createTable commands as a column constraint to give a -- default default_ :: Expression 'Ungrouped '[] '[] db '[] '[] ty -> ColumnTypeExpression db ( 'NoDef :=> ty) -> ColumnTypeExpression db ( 'Def :=> ty) -- | not a true type, but merely a notational convenience for creating -- unique identifier columns with type PGint2 serial2 :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint2) -- | not a true type, but merely a notational convenience for creating -- unique identifier columns with type PGint2 smallserial :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint2) -- | not a true type, but merely a notational convenience for creating -- unique identifier columns with type PGint4 serial4 :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint4) -- | not a true type, but merely a notational convenience for creating -- unique identifier columns with type PGint4 serial :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint4) -- | not a true type, but merely a notational convenience for creating -- unique identifier columns with type PGint8 serial8 :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint8) -- | not a true type, but merely a notational convenience for creating -- unique identifier columns with type PGint8 bigserial :: ColumnTypeExpression db ( 'Def :=> 'NotNull 'PGint8) -- | pgtype is a demoted version of a PGType class PGTyped db (ty :: PGType) pgtype :: PGTyped db ty => TypeExpression db (null ty) -- | Specify TypeExpression from a Haskell type. -- --
-- >>> printSQL $ pgtypeFrom @String -- text ---- --
-- >>> printSQL $ pgtypeFrom @Double -- float8 --pgtypeFrom :: forall hask db null. PGTyped db (PG hask) => TypeExpression db (null (PG hask)) -- | Like PGTyped but also accounts for null. class NullTyped db (ty :: NullType) nulltype :: NullTyped db ty => TypeExpression db ty -- | Specify null TypeExpression from a Haskell type. -- --
-- >>> printSQL $ nulltypeFrom @(Maybe String) -- text ---- --
-- >>> printSQL $ nulltypeFrom @Double -- float8 --nulltypeFrom :: forall hask db. NullTyped db (NullPG hask) => TypeExpression db (NullPG hask) -- | Like PGTyped but also accounts for null. class ColumnTyped db (column :: ColumnType) columntype :: ColumnTyped db column => ColumnTypeExpression db column -- | Specify ColumnTypeExpression from a Haskell type. -- --
-- >>> printSQL $ columntypeFrom @(Maybe String) -- text NULL ---- --
-- >>> printSQL $ columntypeFrom @Double -- float8 NOT NULL --columntypeFrom :: forall hask db. ColumnTyped db ( 'NoDef :=> NullPG hask) => ColumnTypeExpression db ( 'NoDef :=> NullPG hask) -- | Lift PGTyped to a field class FieldTyped db ty fieldtype :: FieldTyped db ty => Aliased (TypeExpression db) ty instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty) instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Type.TypeExpression db ty) instance Squeal.PostgreSQL.Expression.Type.NullTyped db ('Squeal.PostgreSQL.Type.Schema.Null ty) => Squeal.PostgreSQL.Expression.Type.ColumnTyped db ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> 'Squeal.PostgreSQL.Type.Schema.Null ty) instance Squeal.PostgreSQL.Expression.Type.NullTyped db ('Squeal.PostgreSQL.Type.Schema.NotNull ty) => Squeal.PostgreSQL.Expression.Type.ColumnTyped db ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> 'Squeal.PostgreSQL.Type.Schema.NotNull ty) instance (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Expression.Type.NullTyped db ty) => Squeal.PostgreSQL.Expression.Type.FieldTyped db (alias Squeal.PostgreSQL.Type.Alias.::: ty) instance Squeal.PostgreSQL.Expression.Type.PGTyped db ty => Squeal.PostgreSQL.Expression.Type.NullTyped db (null ty) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Type.ColumnTypeExpression db ty) instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGbool instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGint2 instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGint4 instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGint8 instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGnumeric instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGfloat4 instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGfloat8 instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGmoney instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtext instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGchar n) instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGvarchar n) instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGbytea instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtimestamp instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGdate instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtime instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtimetz instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGuuid instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGjson instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGjsonb instance Squeal.PostgreSQL.Expression.Type.PGTyped db pg => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGvararray (null pg)) instance (Data.SOP.Constraint.All GHC.TypeNats.KnownNat dims, Squeal.PostgreSQL.Expression.Type.PGTyped db pg) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGfixarray dims (null pg)) instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtsvector instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGtsquery instance Squeal.PostgreSQL.Expression.Type.PGTyped db 'Squeal.PostgreSQL.Type.Schema.PGoid instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint4) instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGint8) instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGnumeric) instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamp) instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz) instance Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGrange 'Squeal.PostgreSQL.Type.Schema.PGdate) instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGcomposite row))) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGcomposite row) instance (Squeal.PostgreSQL.Type.Schema.UserType db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) Data.Type.Equality.~ '(sch, td), Squeal.PostgreSQL.Type.Alias.Has sch db schema, Squeal.PostgreSQL.Type.Alias.Has td schema ('Squeal.PostgreSQL.Type.Schema.Typedef ('Squeal.PostgreSQL.Type.Schema.PGenum labels))) => Squeal.PostgreSQL.Expression.Type.PGTyped db ('Squeal.PostgreSQL.Type.Schema.PGenum labels) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Type.TypeExpression db 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 :: int4), (7 :: int4), (3 :: int4)) + (365 :: int4)) --(!+) :: TimeOp time diff => Operator (null time) (null diff) (null time) -- |
-- >>> printSQL (365 +! makeDate (1984 :* 7 *: 3)) -- ((365 :: int4) + make_date((1984 :: int4), (7 :: int4), (3 :: int4))) --(+!) :: TimeOp time diff => Operator (null diff) (null time) (null time) -- |
-- >>> printSQL (makeDate (1984 :* 7 *: 3) !- 365) -- (make_date((1984 :: int4), (7 :: int4), (3 :: int4)) - (365 :: int4)) --(!-) :: TimeOp time diff => Operator (null time) (null diff) (null time) -- |
-- >>> printSQL (makeDate (1984 :* 7 *: 3) !-! currentDate) -- (make_date((1984 :: int4), (7 :: int4), (3 :: int4)) - 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 :: int4), (7 :: int4), (3 :: int4)) --makeDate :: '[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 :: int4), (15 :: int4), (23.5 :: float8)) --makeTime :: '[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 :: int4), (7 :: int4), (15 :: int4), (8 :: int4), (15 :: int4), (23.5 :: float8)) --makeTimestamp :: '[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 :: int4), (7 :: int4), (15 :: int4), (8 :: int4), (15 :: int4), (23.5 :: float8)) --makeTimestamptz :: '[null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGint4, null 'PGfloat8] ---> null 'PGtimestamptz -- |
-- >>> printSQL $ interval_ 7 Days -- (INTERVAL '7.000 days') --interval_ :: Milli -> 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.Type.Schema.PGtimestamp 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtimestamptz 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtime 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGtimetz 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGinterval 'Squeal.PostgreSQL.Type.Schema.PGinterval instance Squeal.PostgreSQL.Expression.Time.TimeOp 'Squeal.PostgreSQL.Type.Schema.PGdate 'Squeal.PostgreSQL.Type.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 :: '[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 :: '[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 :: '[null 'PGjsonb, null 'PGjsonb] ---> null 'PGtsvector -- | remove given lexeme from tsvector tsDelete :: '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull 'PGtext))] ---> null 'PGtsvector -- | select only elements with given weights from tsvector tsFilter :: '[null 'PGtsvector, null ( 'PGvararray ( 'NotNull ( 'PGchar 1)))] ---> null 'PGtsvector -- | display a tsquery match tsHeadline :: document `In` '[ 'PGtext, 'PGjson, 'PGjsonb] => '[null document, null 'PGtsquery] ---> null 'PGtext -- | text functions and operators module Squeal.PostgreSQL.Expression.Text -- |
-- >>> printSQL $ lower "ARRRGGG" -- lower((E'ARRRGGG' :: text)) --lower :: null 'PGtext --> null 'PGtext -- |
-- >>> printSQL $ upper "eeee" -- upper((E'eeee' :: text)) --upper :: null 'PGtext --> null 'PGtext -- |
-- >>> printSQL $ charLength "four" -- char_length((E'four' :: text)) --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' :: text) LIKE (E'a%' :: text)) --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' :: text) ILIKE (E'a%' :: text)) --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 grp lat with db params from [Asc] :: Expression grp lat with db params from ( 'NotNull ty) -> SortExpression grp lat with db params from [Desc] :: Expression grp lat with db params from ( 'NotNull ty) -> SortExpression grp lat with db params from [AscNullsFirst] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from [AscNullsLast] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from [DescNullsFirst] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db params from [DescNullsLast] :: Expression grp lat with db params from ( 'Null ty) -> SortExpression grp lat with db 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 grp | expr -> grp orderBy :: OrderBy expr grp => [SortExpression grp lat with db params from] -> expr lat with db params from -> expr lat with db params from instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Sort.SortExpression grp lat with db params from) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Sort.SortExpression grp lat with db params from) instance Squeal.PostgreSQL.Render.RenderSQL [Squeal.PostgreSQL.Expression.Sort.SortExpression grp lat with db params from] -- | range types and functions module Squeal.PostgreSQL.Expression.Range -- | A Range datatype that comprises connected subsets of the real -- line. data Range x Empty :: Range x NonEmpty :: Bound x -> Bound x -> Range x -- | Finite Range constructor (<=..<=) :: x -> x -> Range x infix 4 <=..<= -- | Finite Range constructor (<..<) :: x -> x -> Range x infix 4 <..< -- | Finite Range constructor (<=..<) :: x -> x -> Range x infix 4 <=..< -- | Finite Range constructor (<..<=) :: x -> x -> Range x infix 4 <..<= -- | Half-infinite Range constructor moreThan :: x -> Range x -- | Half-infinite Range constructor atLeast :: x -> Range x -- | Half-infinite Range constructor lessThan :: x -> Range x -- | Half-infinite Range constructor atMost :: x -> Range x -- | A point on the line singleton :: x -> Range x -- | The whole line whole :: Range x -- | The type of Bound for a Range. data Bound x -- | unbounded Infinite :: Bound x -- | inclusive Closed :: x -> Bound x -- | exclusive Open :: x -> Bound x -- | Construct a range -- --
-- >>> printSQL $ range tstzrange (atLeast now)
-- tstzrange(now(), NULL, '[)')
--
-- >>> printSQL $ range numrange (0 <=..< 2*pi)
-- numrange((0.0 :: numeric), ((2.0 :: numeric) * pi()), '[)')
--
-- >>> printSQL $ range int4range Empty
-- ('empty' :: int4range)
--
range :: TypeExpression db (null ( 'PGrange ty)) -> Range (Expression grp lat with db params from ( 'NotNull ty)) -> Expression grp lat with db params from (null ( 'PGrange ty))
-- | range is contained by
(.<@) :: Operator ( 'NotNull ty) (null ( 'PGrange ty)) ( 'Null 'PGbool)
-- | contains range
(@>.) :: Operator (null ( 'PGrange ty)) ( 'NotNull ty) ( 'Null 'PGbool)
-- | strictly left of, return false when an empty range is involved
(<<@) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
-- | strictly right of, return false when an empty range is involved
(@>>) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
-- | does not extend to the right of, return false when an empty range is
-- involved
(&<) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
-- | does not extend to the left of, return false when an empty range is
-- involved
(&>) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
-- | is adjacent to, return false when an empty range is involved
(-|-) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) ( 'Null 'PGbool)
-- | union, will fail if the resulting range would need to contain two
-- disjoint sub-ranges
(@+) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) (null ( 'PGrange ty))
-- | intersection
(@*) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) (null ( 'PGrange ty))
-- | difference, will fail if the resulting range would need to contain two
-- disjoint sub-ranges
(@-) :: Operator (null ( 'PGrange ty)) (null ( 'PGrange ty)) (null ( 'PGrange ty))
-- | lower bound of range
lowerBound :: null ( 'PGrange ty) --> 'Null ty
-- | upper bound of range
upperBound :: null ( 'PGrange ty) --> 'Null ty
-- | is the range empty?
isEmpty :: null ( 'PGrange ty) --> 'Null 'PGbool
-- | is the lower bound inclusive?
lowerInc :: null ( 'PGrange ty) --> 'Null 'PGbool
-- | is the lower bound infinite?
lowerInf :: null ( 'PGrange ty) --> 'Null 'PGbool
-- | is the upper bound inclusive?
upperInc :: null ( 'PGrange ty) --> 'Null 'PGbool
-- | is the upper bound infinite?
upperInf :: null ( 'PGrange ty) --> 'Null 'PGbool
-- | the smallest range which includes both of the given ranges
rangeMerge :: '[null ( 'PGrange ty), null ( 'PGrange ty)] ---> null ( 'PGrange ty)
instance Generics.SOP.Universe.HasDatatypeInfo (Squeal.PostgreSQL.Expression.Range.Range x)
instance Generics.SOP.Universe.Generic (Squeal.PostgreSQL.Expression.Range.Range x)
instance Data.Traversable.Traversable Squeal.PostgreSQL.Expression.Range.Range
instance Data.Foldable.Foldable Squeal.PostgreSQL.Expression.Range.Range
instance GHC.Base.Functor Squeal.PostgreSQL.Expression.Range.Range
instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Range.Range x)
instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Expression.Range.Range x)
instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Expression.Range.Range x)
instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Range.Range x)
instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Range.Range x)
instance Data.Traversable.Traversable Squeal.PostgreSQL.Expression.Range.Bound
instance Data.Foldable.Foldable Squeal.PostgreSQL.Expression.Range.Bound
instance GHC.Base.Functor Squeal.PostgreSQL.Expression.Range.Bound
instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Range.Bound x)
instance GHC.Read.Read x => GHC.Read.Read (Squeal.PostgreSQL.Expression.Range.Bound x)
instance GHC.Show.Show x => GHC.Show.Show (Squeal.PostgreSQL.Expression.Range.Bound x)
instance GHC.Classes.Ord x => GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Range.Bound x)
instance GHC.Classes.Eq x => GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Range.Bound x)
instance Squeal.PostgreSQL.Type.PG.IsPG hask => Squeal.PostgreSQL.Type.PG.IsPG (Squeal.PostgreSQL.Expression.Range.Range hask)
-- | encoding of statement parameters
module Squeal.PostgreSQL.Session.Encode
-- | EncodeParams describes an encoding of a Haskell Type
-- into a list of parameter NullTypes.
--
--
-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"
--
-- >>> :{
-- let
-- encode :: EncodeParams '[]
-- '[ 'NotNull 'PGint2, 'NotNull ('PGchar 1), 'NotNull 'PGtext]
-- (Int16, (Char, String))
-- encode = fst .* fst.snd *. snd.snd
-- in runReaderT (runEncodeParams encode (1,('a',"foo"))) conn
-- :}
-- K (Just "\NUL\SOH") :* K (Just "a") :* K (Just "foo") :* Nil
--
--
-- -- >>> finish conn --newtype EncodeParams (db :: SchemasType) (tys :: [NullType]) (x :: Type) EncodeParams :: (x -> ReaderT (K Connection db) IO (NP (K (Maybe Encoding)) tys)) -> EncodeParams [runEncodeParams] :: EncodeParams -> x -> ReaderT (K Connection db) IO (NP (K (Maybe Encoding)) tys) -- | Parameter encoding for Generic tuples and records. -- --
-- >>> import qualified GHC.Generics as GHC
--
-- >>> import qualified Generics.SOP as SOP
--
-- >>> data Two = Two Int16 String deriving (GHC.Generic, SOP.Generic)
--
-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"
--
-- >>> :{
-- let
-- encode :: EncodeParams '[] '[ 'NotNull 'PGint2, 'NotNull 'PGtext] Two
-- encode = genericParams
-- in runReaderT (runEncodeParams encode (Two 2 "two")) conn
-- :}
-- K (Just "\NUL\STX") :* K (Just "two") :* Nil
--
--
--
-- >>> :{
-- let
-- encode :: EncodeParams '[] '[ 'NotNull 'PGint2, 'NotNull 'PGtext] (Int16, String)
-- encode = genericParams
-- in runReaderT (runEncodeParams encode (2, "two")) conn
-- :}
-- K (Just "\NUL\STX") :* K (Just "two") :* Nil
--
--
-- -- >>> finish conn --genericParams :: forall db params x xs. (IsProductType x xs, AllZip (ToParam db) params xs) => EncodeParams db params x -- | Encode 0 parameters. nilParams :: EncodeParams db '[] x -- | Cons a parameter encoding. -- --
-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"
--
-- >>> :{
-- let
-- encode :: EncodeParams '[]
-- '[ 'Null 'PGint4, 'NotNull 'PGtext]
-- (Maybe Int32, String)
-- encode = fst .* snd .* nilParams
-- in runReaderT (runEncodeParams encode (Nothing, "foo")) conn
-- :}
-- K Nothing :* K (Just "foo") :* Nil
--
--
-- -- >>> finish conn --(.*) :: forall db x0 ty x tys. ToParam db ty x0 => (x -> x0) -> EncodeParams db tys x -> EncodeParams db (ty : tys) x infixr 5 .* -- | End a parameter encoding. -- --
-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"
--
-- >>> :{
-- let
-- encode :: EncodeParams '[]
-- '[ 'Null 'PGint4, 'NotNull 'PGtext, 'NotNull ('PGchar 1)]
-- (Maybe Int32, String, Char)
-- encode = (\(x,_,_) -> x) .* (\(_,y,_) -> y) *. (\(_,_,z) -> z)
-- in runReaderT (runEncodeParams encode (Nothing, "foo", 'z')) conn
-- :}
-- K Nothing :* K (Just "foo") :* K (Just "z") :* Nil
--
--
-- -- >>> finish conn --(*.) :: forall db x x0 ty0 x1 ty1. (ToParam db ty0 x0, ToParam db ty1 x1) => (x -> x0) -> (x -> x1) -> EncodeParams db '[ty0, ty1] x infixl 8 *. -- | Encode 1 parameter. -- --
-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"
--
-- >>> :{
-- let
-- encode :: EncodeParams '[] '[ 'NotNull 'PGint4] Int32
-- encode = aParam
-- in runReaderT (runEncodeParams encode 1776) conn
-- :}
-- K (Just "\NUL\NUL\ACK\240") :* Nil
--
--
-- -- >>> finish conn --aParam :: forall db x. ToParam db (NullPG x) x => EncodeParams db '[NullPG x] x -- | Append parameter encodings. -- --
-- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb"
--
-- >>> :{
-- let
-- encode :: EncodeParams '[]
-- '[ 'NotNull 'PGint4, 'NotNull 'PGint2]
-- (Int32, Int16)
-- encode = contramap fst aParam `appendParams` contramap snd aParam
-- in runReaderT (runEncodeParams encode (1776, 2)) conn
-- :}
-- K (Just "\NUL\NUL\ACK\240") :* K (Just "\NUL\STX") :* Nil
--
--
-- -- >>> finish conn --appendParams :: EncodeParams db params0 x -> EncodeParams db params1 x -> EncodeParams db (Join params0 params1) x -- | A ToPG constraint gives an encoding of a Haskell Type -- into into the binary format of a PostgreSQL PGType. class IsPG x => ToPG (db :: SchemasType) (x :: Type) -- |
-- >>> :set -XTypeApplications -XDataKinds -- -- >>> conn <- connectdb @'[] "host=localhost port=5432 dbname=exampledb" -- -- >>> runReaderT (toPG @'[] False) conn -- "\NUL" ---- --
-- >>> runReaderT (toPG @'[] (0 :: Int16)) conn -- "\NUL\NUL" ---- --
-- >>> runReaderT (toPG @'[] (0 :: Int32)) conn -- "\NUL\NUL\NUL\NUL" ---- --
-- >>> :set -XMultiParamTypeClasses -XGeneralizedNewtypeDeriving
--
-- >>> newtype UserId = UserId { getUserId :: Int64 } deriving newtype (IsPG, ToPG db)
--
-- >>> runReaderT (toPG @'[] (UserId 0)) conn
-- "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL"
--
--
-- -- >>> finish conn --toPG :: ToPG db x => x -> ReaderT (K Connection db) IO Encoding -- | A ToParam constraint gives an encoding of a Haskell Type -- into into the binary format of a PostgreSQL NullType. You -- should not define instances for ToParam, just use the provided -- instances. class ToParam (db :: SchemasType) (ty :: NullType) (x :: Type) toParam :: ToParam db ty x => x -> ReaderT (K Connection db) IO (Maybe Encoding) -- | A ToField constraint lifts the ToPG parser to an -- encoding of a (Symbol, Type) to a (Symbol, -- NullityType), encoding Nulls to Maybes. You should -- not define instances for ToField, just use the provided -- instances. class ToField (db :: SchemasType) (field :: (Symbol, NullType)) (x :: (Symbol, Type)) toField :: ToField db field x => P x -> ReaderT (K Connection db) IO (K (Maybe Encoding) field) -- | A ToArray constraint gives an encoding of a Haskell Type -- into the binary format of a PostgreSQL fixed-length array. You should -- not define instances for ToArray, just use the provided -- instances. class ToArray (db :: SchemasType) (dims :: [Nat]) (ty :: NullType) (x :: Type) arrayPayload :: ToArray db dims ty x => x -> ReaderT (K Connection db) IO Encoding arrayDims :: ToArray db dims ty x => [Int32] arrayNulls :: ToArray db dims ty x => Bool instance Data.Functor.Contravariant.Contravariant (Squeal.PostgreSQL.Session.Encode.EncodeParams db tys) instance (Squeal.PostgreSQL.Type.PG.NullPG x Data.Type.Equality.~ ty, Squeal.PostgreSQL.Session.Encode.ToArray db '[] ty x, Squeal.PostgreSQL.Session.Oid.OidOfNull db ty) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.VarArray [x]) instance (Squeal.PostgreSQL.Type.PG.NullPG x Data.Type.Equality.~ ty, Squeal.PostgreSQL.Session.Encode.ToArray db '[] ty x, Squeal.PostgreSQL.Session.Oid.OidOfNull db ty) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector x)) instance (Squeal.PostgreSQL.Session.Encode.ToArray db dims ty x, Squeal.PostgreSQL.Session.Oid.OidOfNull db ty) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.FixArray x) instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToArray db '[] ('Squeal.PostgreSQL.Type.Schema.NotNull pg) x instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToArray db '[] ('Squeal.PostgreSQL.Type.Schema.Null pg) (GHC.Maybe.Maybe x) instance (Generics.SOP.Universe.IsProductType tuple xs, Squeal.PostgreSQL.Type.List.Length xs Data.Type.Equality.~ dim, Data.SOP.Constraint.All ((Data.Type.Equality.~) x) xs, Squeal.PostgreSQL.Session.Encode.ToArray db dims ty x, GHC.TypeNats.KnownNat dim) => Squeal.PostgreSQL.Session.Encode.ToArray db (dim : dims) ty tuple instance (Data.SOP.Constraint.SListI fields, Generics.SOP.Record.IsRecord x xs, Data.SOP.Constraint.AllZip (Squeal.PostgreSQL.Session.Encode.ToField db) fields xs, Data.SOP.Constraint.All (Squeal.PostgreSQL.Session.Oid.OidOfField db) fields, Squeal.PostgreSQL.Type.PG.RowPG x Data.Type.Equality.~ fields) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Composite x) instance (fld0 Data.Type.Equality.~ fld1, Squeal.PostgreSQL.Session.Encode.ToParam db ty x) => Squeal.PostgreSQL.Session.Encode.ToField db (fld0 Squeal.PostgreSQL.Type.Alias.::: ty) (fld1 Squeal.PostgreSQL.Type.Alias.::: x) instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToParam db ('Squeal.PostgreSQL.Type.Schema.NotNull pg) x instance (Squeal.PostgreSQL.Session.Encode.ToPG db x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Session.Encode.ToParam db ('Squeal.PostgreSQL.Type.Schema.Null pg) (GHC.Maybe.Maybe x) instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Bool instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Int.Int16 instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Int.Int32 instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Int.Int64 instance Squeal.PostgreSQL.Session.Encode.ToPG db Database.PostgreSQL.LibPQ.Oid instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Float instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Double instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Scientific.Scientific instance Squeal.PostgreSQL.Session.Encode.ToPG db Squeal.PostgreSQL.Type.Money instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.UUID.Types.Internal.UUID instance Squeal.PostgreSQL.Session.Encode.ToPG db (Network.IP.Addr.NetAddr Network.IP.Addr.IP) instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Types.Char instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Text.Internal.Text instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Text.Internal.Lazy.Text instance Squeal.PostgreSQL.Session.Encode.ToPG db GHC.Base.String instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.ByteString.Internal.ByteString instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.ByteString.Lazy.Internal.ByteString instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.Calendar.Days.Day instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay instance Squeal.PostgreSQL.Session.Encode.ToPG db (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone) instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.LocalTime.Internal.LocalTime.LocalTime instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.Clock.Internal.UTCTime.UTCTime instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Time.Clock.Internal.DiffTime.DiffTime instance Squeal.PostgreSQL.Session.Encode.ToPG db Data.Aeson.Types.Internal.Value instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Json x) instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Jsonb x) instance (Generics.SOP.Universe.IsEnumType x, Generics.SOP.Universe.HasDatatypeInfo x, Squeal.PostgreSQL.Type.PG.LabelsPG x Data.Type.Equality.~ labels) => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Type.Enumerated x) instance Squeal.PostgreSQL.Session.Encode.ToPG db x => Squeal.PostgreSQL.Session.Encode.ToPG db (Squeal.PostgreSQL.Expression.Range.Range x) -- | decoding of result values module Squeal.PostgreSQL.Session.Decode -- | A FromPG constraint gives a parser from the binary format of a -- PostgreSQL PGType into a Haskell Type. class IsPG y => FromPG y -- |
-- >>> :set -XMultiParamTypeClasses -XGeneralizedNewtypeDeriving -XDerivingStrategies -XDerivingVia -XUndecidableInstances
--
-- >>> import GHC.Generics as GHC
--
-- >>> :{
-- newtype UserId = UserId { getId :: Int64 }
-- deriving newtype (IsPG, FromPG)
-- :}
--
--
--
-- >>> :{
-- data Complex = Complex
-- { real :: Double
-- , imaginary :: Double
-- } deriving stock GHC.Generic
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- deriving (IsPG, FromPG) via (Composite Complex)
-- :}
--
--
--
-- >>> :{
-- data Direction = North | South | East | West
-- deriving stock GHC.Generic
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- deriving (IsPG, FromPG) via (Enumerated Direction)
-- :}
--
fromPG :: FromPG y => StateT ByteString (Except Text) y
-- | Converts a Value type from postgresql-binary for use
-- in the fromPG method of FromPG.
devalue :: Value x -> StateT ByteString (Except Text) x
-- |
-- >>> :set -XTypeFamilies
--
-- >>> :{
-- data Complex = Complex
-- { real :: Double
-- , imaginary :: Double
-- }
-- instance IsPG Complex where
-- type PG Complex = 'PGcomposite '[
-- "re" ::: 'NotNull 'PGfloat8,
-- "im" ::: 'NotNull 'PGfloat8]
-- instance FromPG Complex where
-- fromPG = rowValue $ do
-- re <- #re
-- im <- #im
-- return Complex {real = re, imaginary = im}
-- :}
--
rowValue :: (PG y ~ 'PGcomposite row, SListI row) => DecodeRow row y -> StateT ByteString (Except Text) y
-- | DecodeRow describes a decoding of a PostgreSQL RowType
-- into a Haskell Type.
--
-- DecodeRow has an interface given by the classes Functor,
-- Applicative, Alternative, Monad,
-- MonadPlus, MonadError Text, and IsLabel.
--
--
-- >>> :set -XOverloadedLabels
--
-- >>> :{
-- let
-- decode :: DecodeRow
-- '[ "fst" ::: 'NotNull 'PGint2, "snd" ::: 'NotNull ('PGchar 1)]
-- (Int16, Char)
-- decode = (,) <$> #fst <*> #snd
-- in runDecodeRow decode (SOP.K (Just "\NUL\SOH") :* SOP.K (Just "a") :* Nil)
-- :}
-- Right (1,'a')
--
--
-- There is also an IsLabel instance for MaybeT
-- DecodeRows, useful for decoding outer joined rows.
--
--
-- >>> :{
-- let
-- decode :: DecodeRow
-- '[ "fst" ::: 'Null 'PGint2, "snd" ::: 'Null ('PGchar 1)]
-- (Maybe (Int16, Char))
-- decode = runMaybeT $ (,) <$> #fst <*> #snd
-- in runDecodeRow decode (SOP.K (Just "\NUL\SOH") :* SOP.K (Just "a") :* Nil)
-- :}
-- Right (Just (1,'a'))
--
newtype DecodeRow (row :: RowType) (y :: Type)
DecodeRow :: ReaderT (NP (K (Maybe ByteString)) row) (Except Text) y -> DecodeRow
[unDecodeRow] :: DecodeRow -> ReaderT (NP (K (Maybe ByteString)) row) (Except Text) y
-- | Smart constructor for a DecodeRow.
decodeRow :: (NP (K (Maybe ByteString)) row -> Either Text y) -> DecodeRow row y
-- | Run a DecodeRow.
runDecodeRow :: DecodeRow row y -> NP (K (Maybe ByteString)) row -> Either Text y
-- | Row decoder for Generic records.
--
--
-- >>> import qualified GHC.Generics as GHC
--
-- >>> import qualified Generics.SOP as SOP
--
-- >>> data Two = Two {frst :: Int16, scnd :: String} deriving (Show, GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)
--
-- >>> :{
-- let
-- decode :: DecodeRow '[ "frst" ::: 'NotNull 'PGint2, "scnd" ::: 'NotNull 'PGtext] Two
-- decode = genericRow
-- in runDecodeRow decode (SOP.K (Just "\NUL\STX") :* SOP.K (Just "two") :* Nil)
-- :}
-- Right (Two {frst = 2, scnd = "two"})
--
genericRow :: forall row y ys. (IsRecord y ys, AllZip FromField row ys) => DecodeRow row y
-- | A FromValue constraint lifts the FromPG parser to a
-- decoding of a NullityType to a Type, decoding
-- Nulls to Maybes. You should not define instances for
-- FromValue, just use the provided instances.
class FromValue (ty :: NullType) (y :: Type)
fromValue :: FromValue ty y => Maybe ByteString -> Either Text y
-- | A FromField constraint lifts the FromPG 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 (field :: (Symbol, NullType)) (y :: (Symbol, Type))
fromField :: FromField field y => Maybe ByteString -> Either Text (P y)
-- | A FromArray constraint gives a decoding to a Haskell
-- Type from the binary format of a PostgreSQL fixed-length array.
-- You should not define instances for FromArray, just use the
-- provided instances.
class FromArray (dims :: [Nat]) (ty :: NullType) (y :: Type)
fromArray :: FromArray dims ty y => Array y
-- | A state transformer monad parameterized by:
--
--
-- >>> let expr = parameter @1 int4 :: Expression lat '[] grp db '[ 'Null 'PGint4] from ('Null 'PGint4)
--
-- >>> printSQL expr
-- ($1 :: int4)
--
parameter :: HasParameter n params ty => TypeExpression db ty -> Expression grp lat with db params from ty
-- | param takes a Nat using type application and for basic
-- types, infers a TypeExpression.
--
--
-- >>> let expr = param @1 :: Expression grp lat with db '[ 'Null 'PGint4] from ('Null 'PGint4)
--
-- >>> printSQL expr
-- ($1 :: int4)
--
param :: forall n ty lat with db params from grp. (NullTyped db ty, HasParameter n params ty) => Expression grp lat with db params from ty
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
-- | math functions
module Squeal.PostgreSQL.Expression.Math
-- |
-- >>> :{
-- let
-- expression :: Expr (null 'PGfloat4)
-- expression = atan2_ (pi *: 2)
-- in printSQL expression
-- :}
-- atan2(pi(), (2.0 :: float4))
--
atan2_ :: float `In` PGFloating => '[null float, null float] ---> null float
-- | integer division, truncates the result
--
--
-- >>> :{
-- let
-- expression :: Expression grp lat with db params from (null 'PGint2)
-- expression = 5 `quot_` 2
-- in printSQL expression
-- :}
-- ((5 :: int2) / (2 :: int2))
--
quot_ :: int `In` PGIntegral => Operator (null int) (null int) (null int)
-- | remainder upon integer division
--
--
-- >>> :{
-- let
-- expression :: Expression grp lat with db params from (null 'PGint2)
-- expression = 5 `rem_` 2
-- in printSQL expression
-- :}
-- ((5 :: int2) % (2 :: int2))
--
rem_ :: int `In` PGIntegral => Operator (null int) (null int) (null int)
-- |
-- >>> :{
-- let
-- expression :: Expression grp lat with db params from (null 'PGfloat4)
-- expression = trunc pi
-- in printSQL expression
-- :}
-- trunc(pi())
--
trunc :: frac `In` PGFloating => null frac --> null frac
-- |
-- >>> :{
-- let
-- expression :: Expression grp lat with db params from (null 'PGfloat4)
-- expression = round_ pi
-- in printSQL expression
-- :}
-- round(pi())
--
round_ :: frac `In` PGFloating => null frac --> null frac
-- |
-- >>> :{
-- let
-- expression :: Expression grp lat with db params from (null 'PGfloat4)
-- expression = ceiling_ pi
-- in printSQL expression
-- :}
-- ceiling(pi())
--
ceiling_ :: frac `In` PGFloating => null frac --> null frac
-- | 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 grp lat with db params from = Expression grp lat with db 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 grp lat with db params from (null 'PGint2)
-- expression = caseWhenThenElse [(true, 1), (false, 2)] 3
-- in printSQL expression
-- :}
-- CASE WHEN TRUE THEN (1 :: int2) WHEN FALSE THEN (2 :: int2) ELSE (3 :: int2) END
--
caseWhenThenElse :: [(Condition grp lat with db params from, Expression grp lat with db params from ty)] -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty
-- |
-- >>> :{
-- let
-- expression :: Expression grp lat with db params from (null 'PGint2)
-- expression = ifThenElse true 1 0
-- in printSQL expression
-- :}
-- CASE WHEN TRUE THEN (1 :: int2) ELSE (0 :: int2) END
--
ifThenElse :: Condition grp lat with db params from -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty -> Expression grp lat with db params from ty
-- | intermediate table expressions
module Squeal.PostgreSQL.Query.Table
-- | 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 (grp :: Grouping) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
TableExpression :: FromClause lat with db params from -> [Condition 'Ungrouped lat with db params from] -> GroupByClause grp from -> HavingClause grp lat with db params from -> [SortExpression grp lat with db params from] -> [Word64] -> [Word64] -> TableExpression
-- | 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 lat with db params from
-- | optional search coditions, combined with .&&. After the
-- processing of the fromClause is done, each row of the derived
-- virtual table is checked against the search condition. If the result
-- of the condition is true, the row is kept in the output table,
-- otherwise it is discarded. The search condition typically references
-- at least one column of the table generated in the fromClause;
-- this is not required, but otherwise the WHERE clause will be fairly
-- useless.
[whereClause] :: TableExpression -> [Condition 'Ungrouped lat with db 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 grp lat with db params from
-- | The orderByClause is for optional sorting. When more than one
-- SortExpression is specified, the later (right) values are used
-- to sort rows that are equal according to the earlier (left) values.
[orderByClause] :: TableExpression -> [SortExpression grp lat with db 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 lat with db params from -> TableExpression 'Ungrouped lat with db params from
-- | A where_ is an endomorphism of TableExpressions which
-- adds a search condition to the whereClause.
where_ :: Condition 'Ungrouped lat with db params from -> TableExpression grp lat with db params from -> TableExpression grp lat with db 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 'Ungrouped lat with db params from -> TableExpression ( 'Grouped bys) lat with db params from
-- | A having is an endomorphism of TableExpressions which
-- adds a search condition to the havingClause.
having :: Condition ( 'Grouped bys) lat with db params from -> TableExpression ( 'Grouped bys) lat with db params from -> TableExpression ( 'Grouped bys) lat with db params from
-- | A limit is an endomorphism of TableExpressions which
-- adds to the limitClause.
limit :: Word64 -> TableExpression grp lat with db params from -> TableExpression grp lat with db params from
-- | An offset is an endomorphism of TableExpressions which
-- adds to the offsetClause.
offset :: Word64 -> TableExpression grp lat with db params from -> TableExpression grp lat with db params from
-- | 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.
newtype GroupByClause grp from
UnsafeGroupByClause :: ByteString -> GroupByClause grp from
[renderGroupByClause] :: GroupByClause grp from -> ByteString
-- | A HavingClause is used to eliminate groups that are not of
-- interest. An Ungrouped TableExpression may only use
-- NoHaving while a Grouped TableExpression must use
-- Having whose conditions are combined with .&&.
data HavingClause grp lat with db params from
[NoHaving] :: HavingClause 'Ungrouped lat with db params from
[Having] :: [Condition ( 'Grouped bys) lat with db params from] -> HavingClause ( 'Grouped bys) lat with db params from
instance GHC.Generics.Generic (Squeal.PostgreSQL.Query.Table.TableExpression grp lat with db params from)
instance forall k1 (grp :: k1) k2 (from :: k2). Control.DeepSeq.NFData (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Classes.Ord (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Classes.Eq (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Show.Show (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
instance forall k1 (grp :: k1) k2 (from :: k2). GHC.Generics.Generic (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
instance GHC.Show.Show (Squeal.PostgreSQL.Query.Table.By from by)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Table.By from by)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Table.By from by)
instance GHC.Show.Show (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.TableExpression grp lat with db params from)
instance Squeal.PostgreSQL.Expression.Sort.OrderBy (Squeal.PostgreSQL.Query.Table.TableExpression grp) grp
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.HavingClause grp lat with db params from)
instance forall k1 k2 (grp :: k2) (from :: k1). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.GroupByClause grp from)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Table.By from by)
instance (Squeal.PostgreSQL.Type.Alias.HasUnique rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, by Data.Type.Equality.~ '(rel, col)) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Table.By rels by)
instance (Squeal.PostgreSQL.Type.Alias.HasUnique rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, bys Data.Type.Equality.~ '[ '(rel, col)]) => GHC.OverloadedLabels.IsLabel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Query.Table.By rels) bys)
instance (Squeal.PostgreSQL.Type.Alias.Has rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, by Data.Type.Equality.~ '(rel, col)) => Squeal.PostgreSQL.Type.Alias.IsQualified rel col (Squeal.PostgreSQL.Query.Table.By rels by)
instance (Squeal.PostgreSQL.Type.Alias.Has rel rels cols, Squeal.PostgreSQL.Type.Alias.Has col cols ty, bys Data.Type.Equality.~ '[ '(rel, col)]) => Squeal.PostgreSQL.Type.Alias.IsQualified rel col (Data.SOP.NP.NP (Squeal.PostgreSQL.Query.Table.By rels) bys)
-- | Squeal joins
module Squeal.PostgreSQL.Query.From.Join
-- | A JoinItem is the right hand side of a cross,
-- inner, leftOuter, rightOuter, fullOuter
-- join of FromClauses.
data JoinItem (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (left :: FromType) (right :: FromType)
[Join] :: FromClause lat with db params right -> JoinItem lat with db params left right
[JoinLateral] :: Aliased (Query (Join lat left) with db params) query -> JoinItem lat with db params left '[query]
[JoinFunction] :: SetFun db arg set -> Expression 'Ungrouped lat with db params left arg -> JoinItem lat with db params left '[set]
[JoinFunctionN] :: SListI args => SetFunN db args set -> NP (Expression 'Ungrouped lat with db params left) args -> JoinItem lat with db params left '[set]
-- | left & cross (Join right). For every possible combination
-- of rows from left and right (i.e., a Cartesian
-- product), the joined table will contain a row consisting of all
-- columns in left followed by all columns in right. If
-- the tables have n and m rows respectively, the
-- joined table will have n * m rows.
cross :: JoinItem lat with db params left right -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
-- | left & crossJoin right. For every possible combination of
-- rows from left and right (i.e., a Cartesian
-- product), the joined table will contain a row consisting of all
-- columns in left followed by all columns in right. If
-- the tables have n and m rows respectively, the
-- joined table will have n * m rows.
crossJoin :: FromClause lat with db params right -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
-- | Like crossJoin with a subquery but allowed to reference
-- columns provided by preceding FromClause items.
crossJoinLateral :: Aliased (Query (Join lat left) with db params) query -> FromClause lat with db params left -> FromClause lat with db params (Join left '[query])
-- | left & inner (Join right) on. The joined table is
-- filtered by the on condition.
inner :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
-- | left & innerJoin right on. The joined table is filtered
-- by the on condition.
innerJoin :: FromClause lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left right)
-- | Like innerJoin with a subquery but allowed to reference
-- columns provided by preceding FromClause items.
innerJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (Join left '[query])
-- | left & leftOuter (Join right) on. First, an inner join is
-- performed. Then, for each row in left that does not satisfy
-- the on condition with any row in right, a joined row
-- is added with null values in columns of right. Thus, the
-- joined table always has at least one row for each row in
-- left.
leftOuter :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left (NullifyFrom 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 lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join left (NullifyFrom right))
-- | Like leftOuterJoin with a subquery but allowed to
-- reference columns provided by preceding FromClause items.
leftOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (Join left (NullifyFrom '[query]))
-- | left & rightOuter (Join right) on. First, an inner join
-- is performed. Then, for each row in right that does not
-- satisfy the on condition with any row in left, a
-- joined row is added with null values in columns of left. This
-- is the converse of a left join: the result table will always have a
-- row for each row in right.
rightOuter :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join (NullifyFrom left) 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 lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (Join (NullifyFrom left) right)
-- | Like rightOuterJoin with a subquery but allowed to
-- reference columns provided by preceding FromClause items.
rightOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (Join (NullifyFrom left) '[query])
-- | left & fullOuter (Join right) on. First, an inner join is
-- performed. Then, for each row in left that does not satisfy
-- the on condition with any row in right, a joined row
-- is added with null values in columns of right. Also, for each
-- row of right that does not satisfy the join condition with
-- any row in left, a joined row with null values in the columns
-- of left is added.
fullOuter :: JoinItem lat with db params left right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (NullifyFrom (Join 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 lat with db params right -> Condition 'Ungrouped lat with db params (Join left right) -> FromClause lat with db params left -> FromClause lat with db params (NullifyFrom (Join left right))
-- | Like fullOuterJoin with a subquery but allowed to
-- reference columns provided by preceding FromClause items.
fullOuterJoinLateral :: Aliased (Query (Join lat left) with db params) query -> Condition 'Ungrouped lat with db params (Join left '[query]) -> FromClause lat with db params left -> FromClause lat with db params (NullifyFrom (Join left '[query]))
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.From.Join.JoinItem lat with db params left right)
-- | subquery expressions
module Squeal.PostgreSQL.Expression.Subquery
-- | The argument of exists is an arbitrary subquery. The subquery
-- is evaluated to determine whether it returns any rows. If it returns
-- at least one row, the result of exists is true; if the
-- subquery returns no rows, the result of exists is false.
--
-- The subquery can refer to variables from the surrounding query, which
-- will act as constants during any one evaluation of the subquery.
--
-- The subquery will generally only be executed long enough to determine
-- whether at least one row is returned, not all the way to completion.
exists :: Query (Join lat from) with db params row -> Expression grp lat with db params from (null 'PGbool)
-- | The result is true if the left-hand expression's result is
-- equal to any of the right-hand expressions.
--
-- -- >>> printSQL $ true `in_` [true, false, null_] -- TRUE IN (TRUE, FALSE, NULL) --in_ :: Expression grp lat with db params from ty -> [Expression grp lat with db params from ty] -> Expression grp lat with db params from (null 'PGbool) -- | 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 grp lat with db params from ty -> [Expression grp lat with db params from ty] -> Expression grp lat with db params from (null 'PGbool) -- | 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 grp lat with db params from ty1 -> Operator ty1 ty2 ( 'Null 'PGbool) -> Query (Join lat from) with db params '[col ::: ty2] -> Condition grp lat with db params from
-- | 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' :: text) LIKE ANY (SELECT * FROM (VALUES ((E'foobar' :: text))) AS t ("foo")))
--
subAny :: Expression grp lat with db params from ty1 -> Operator ty1 ty2 ( 'Null 'PGbool) -> Query (Join lat from) with db params '[col ::: ty2] -> Condition grp lat with db params from
-- | null expressions and handlers
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 -- | Analagous to fromJust inverse to notNull, useful when -- you know an Expression is NotNull, because, for -- instance, you've filtered out NULL values in a column. unsafeNotNull :: 'Null ty --> 'NotNull ty -- | Some expressions are null polymorphic which may raise inference -- issues. Use monoNotNull to fix their nullity as NotNull. monoNotNull :: (forall null. Expression grp lat with db params from (null ty)) -> Expression grp lat with db params from ( 'NotNull ty) -- | return the leftmost value which is not NULL -- --
-- >>> printSQL $ coalesce [null_, true] false -- COALESCE(NULL, TRUE, FALSE) --coalesce :: FunctionVar ( 'Null ty) (null ty) (null ty) -- | analagous to fromMaybe using COALESCE -- --
-- >>> printSQL $ fromNull true null_ -- COALESCE(NULL, TRUE) --fromNull :: Expression grp lat with db params from ( 'NotNull ty) -> Expression grp lat with db params from ( 'Null ty) -> Expression grp lat with db params from ( 'NotNull ty) -- |
-- >>> 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 grp lat with db params from nullty -> (Expression grp lat with db params from ( 'NotNull ty) -> Expression grp lat with db params from nullty) -> Expression grp lat with db params from ( 'Null ty) -> Expression grp lat with db params from nullty -- | right inverse to fromNull, if its arguments are equal then -- nullIf gives NULL. -- --
-- >>> :set -XTypeApplications -XDataKinds
--
-- >>> let expr = nullIf (false *: param @1) :: Expression grp lat with db '[ 'NotNull 'PGbool] from ('Null 'PGbool)
--
-- >>> printSQL expr
-- NULLIF(FALSE, ($1 :: bool))
--
nullIf :: '[ 'NotNull ty, 'NotNull ty] ---> 'Null 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 => tuple ---> null 'PGjson
-- | Builds a possibly-heterogeneously-typed (binary) JSON array out of a
-- variadic argument list.
jsonbBuildArray :: SListI tuple => 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 => tys ---> null 'PGjson
jsonbBuildObject :: JsonBuildObject tys => 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 :: '[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 :: '[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 :: '[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 :: '[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 (inline (Json (object ["a" .= "foo", "b" .= "bar"]))))))
-- SELECT * FROM json_each(('{"a":"foo","b":"bar"}' :: json))
--
jsonEach :: null 'PGjson -|-> ("json_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson])
-- | Expands the outermost binary JSON object into a set of key/value
-- pairs.
--
--
-- >>> printSQL (select Star (from (jsonbEach (inline (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))))
-- SELECT * FROM jsonb_each(('{"a":"foo","b":"bar"}' :: jsonb))
--
jsonbEach :: null 'PGjsonb -|-> ("jsonb_each" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGjson])
-- | Expands the outermost JSON object into a set of key/value pairs.
--
--
-- >>> printSQL (select Star (from (jsonEachText (inline (Json (object ["a" .= "foo", "b" .= "bar"]))))))
-- SELECT * FROM json_each_text(('{"a":"foo","b":"bar"}' :: json))
--
jsonEachText :: null 'PGjson -|-> ("json_each_text" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext])
-- | Expands the outermost binary JSON object into a set of key/value
-- pairs.
--
--
-- >>> printSQL (select Star (from (jsonbEachText (inline (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))))
-- SELECT * FROM jsonb_each_text(('{"a":"foo","b":"bar"}' :: jsonb))
--
jsonbEachText :: null 'PGjsonb -|-> ("jsonb_each_text" ::: '["key" ::: 'NotNull 'PGtext, "value" ::: 'NotNull 'PGtext])
-- | Returns set of keys in the outermost JSON object.
--
--
-- >>> printSQL (jsonObjectKeys (inline (Json (object ["a" .= "foo", "b" .= "bar"]))))
-- json_object_keys(('{"a":"foo","b":"bar"}' :: json))
--
jsonObjectKeys :: null 'PGjson -|-> ("json_object_keys" ::: '["json_object_keys" ::: 'NotNull 'PGtext])
-- | Returns set of keys in the outermost JSON object.
--
--
-- >>> printSQL (jsonbObjectKeys (inline (Jsonb (object ["a" .= "foo", "b" .= "bar"]))))
-- jsonb_object_keys(('{"a":"foo","b":"bar"}' :: jsonb))
--
jsonbObjectKeys :: null 'PGjsonb -|-> ("jsonb_object_keys" ::: '["jsonb_object_keys" ::: 'NotNull 'PGtext])
-- | Build rows from Json types.
type JsonPopulateFunction fun json = forall db row lat with params. json `In` PGJsonType => TypeExpression db ( 'NotNull ( 'PGcomposite row)) " row type" -> Expression 'Ungrouped lat with db params '[] ( 'NotNull json) " json type" -> FromClause lat with db params '[fun ::: row]
-- | 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 lat with db params tab row. (SListI row, json `In` PGJsonType) => Expression 'Ungrouped lat with db params '[] ( 'NotNull json) " json type" -> Aliased (NP (Aliased (TypeExpression db))) (tab ::: row) " row type" -> FromClause lat with db params '[tab ::: row]
-- | 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.Type.List.In key Squeal.PostgreSQL.Type.Schema.PGJsonKey) => Squeal.PostgreSQL.Expression.Json.JsonBuildObject ('Squeal.PostgreSQL.Type.Schema.NotNull key : value : tys)
-- | composite functions
module Squeal.PostgreSQL.Expression.Composite
-- | A row constructor is an expression that builds a row value (also
-- called a composite value) using values for its member fields.
--
--
-- >>> :{
-- type Complex = 'PGcomposite
-- '[ "real" ::: 'NotNull 'PGfloat8
-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
-- :}
--
--
--
-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression grp lat with db params from ('NotNull Complex)
--
-- >>> printSQL i
-- ROW((0.0 :: float8), (1.0 :: float8))
--
row :: SListI row => NP (Aliased (Expression grp lat with db params from)) row -> Expression grp lat with db params from (null ( 'PGcomposite row))
-- | A row constructor on all columns in a table expression.
rowStar :: Has tab from row => Alias tab -> Expression grp lat with db params from (null ( 'PGcomposite row))
-- |
-- >>> :{
-- type Complex = 'PGcomposite
-- '[ "real" ::: 'NotNull 'PGfloat8
-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
-- type Schema = '["complex" ::: 'Typedef Complex]
-- :}
--
--
--
-- >>> let i = row (0 `as` #real :* 1 `as` #imaginary) :: Expression lat '[] grp (Public Schema) from params ('NotNull Complex)
--
-- >>> printSQL $ i & field #complex #imaginary
-- (ROW((0.0 :: float8), (1.0 :: float8))::"complex")."imaginary"
--
field :: (Has sch db schema, Has tydef schema ( 'Typedef ( 'PGcomposite row)), Has field row ty) => QualifiedAlias sch tydef -> Alias field -> Expression grp lat with db params from ( 'NotNull ( 'PGcomposite row)) -> Expression grp lat with db params from 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 grp lat with db '[ '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 grp lat with db params from ty. Expression grp lat with db params from ty -> (Expression grp lat with db params from ty, Expression grp lat with db params from ty) " bounds" -> Condition grp lat with db params from -- |
-- >>> 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 -- | array functions module Squeal.PostgreSQL.Expression.Array -- | Construct an array. -- --
-- >>> printSQL $ array [null_, false, true] -- ARRAY[NULL, FALSE, TRUE] --array :: [Expression grp lat with db params from ty] -> Expression grp lat with db params from (null ( 'PGvararray ty)) -- | Safely construct an empty array. -- --
-- >>> printSQL $ array0 text -- (ARRAY[] :: text[]) --array0 :: TypeExpression db ty -> Expression grp lat with db params from (null ( 'PGvararray ty)) -- | Construct a fixed length array. -- --
-- >>> printSQL $ array1 (null_ :* false *: true) -- ARRAY[NULL, FALSE, TRUE] ---- --
-- >>> :type array1 (null_ :* false *: true)
-- array1 (null_ :* false *: true)
-- :: Expression
-- grp
-- lat
-- with
-- db
-- params
-- from
-- (null ('PGfixarray '[3] ('Null 'PGbool)))
--
array1 :: (n ~ Length tys, All ((~) ty) tys) => NP (Expression grp lat with db params from) tys -> Expression grp lat with db params from (null ( 'PGfixarray '[n] ty))
-- | Construct a fixed size matrix.
--
-- -- >>> printSQL $ array2 ((null_ :* false *: true) *: (false :* null_ *: true)) -- ARRAY[[NULL, FALSE, TRUE], [FALSE, NULL, TRUE]] ---- --
-- >>> :type array2 ((null_ :* false *: true) *: (false :* null_ *: true))
-- array2 ((null_ :* false *: true) *: (false :* null_ *: true))
-- :: Expression
-- grp
-- lat
-- with
-- db
-- params
-- from
-- (null ('PGfixarray '[2, 3] ('Null 'PGbool)))
--
array2 :: (All ((~) tys) tyss, All SListI tyss, Length tyss ~ n1, All ((~) ty) tys, Length tys ~ n2) => NP (NP (Expression grp lat with db params from)) tyss -> Expression grp lat with db params from (null ( 'PGfixarray '[n1, n2] ty))
-- | -- >>> 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 -- --
-- >>> printSQL $ unnest (array [null_, false, true]) -- unnest(ARRAY[NULL, FALSE, TRUE]) --unnest :: null ( 'PGvararray ty) -|-> ("unnest" ::: '["unnest" ::: ty]) -- | inline expressions module Squeal.PostgreSQL.Expression.Inline -- | The Inline class allows embedding a Haskell value directly as -- an Expression using inline. -- --
-- >>> printSQL (inline 'a') -- (E'a' :: char(1)) ---- --
-- >>> printSQL (inline (1 :: Double)) -- (1.0 :: float8) ---- --
-- >>> printSQL (inline (Json ([1, 2] :: [Double])))
-- ('[1.0,2.0]' :: json)
--
--
-- -- >>> printSQL (inline (Enumerated GT)) -- 'GT' --class Inline x inline :: Inline x => x -> Expr (null (PG x)) -- | Lifts Inline to NullTypes. class InlineParam x ty inlineParam :: InlineParam x ty => x -> Expr ty -- | Lifts Inline to fields. class InlineField (field :: (Symbol, Type)) (fieldpg :: (Symbol, NullType)) inlineField :: InlineField field fieldpg => P field -> Aliased (Expression grp lat with db params from) fieldpg -- | Use a Haskell record as a inline a row of expressions. inlineFields :: (IsRecord hask fields, AllZip InlineField fields row) => hask -> NP (Aliased (Expression 'Ungrouped '[] with db params '[])) row -- | Lifts Inline to a column entry class InlineColumn (field :: (Symbol, Type)) (column :: (Symbol, ColumnType)) -- | Haskell record field as a inline column inlineColumn :: InlineColumn field column => P field -> Aliased (Optional (Expression grp lat with db params from)) column -- | Use a Haskell record as a inline list of columns inlineColumns :: (IsRecord hask xs, AllZip InlineColumn xs columns) => hask -> NP (Aliased (Optional (Expression 'Ungrouped '[] with db params '[]))) columns instance (GHC.TypeLits.KnownSymbol col, Squeal.PostgreSQL.Expression.Inline.InlineParam x ty) => Squeal.PostgreSQL.Expression.Inline.InlineColumn (col Squeal.PostgreSQL.Type.Alias.::: x) (col Squeal.PostgreSQL.Type.Alias.::: ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> ty)) instance (GHC.TypeLits.KnownSymbol col, Squeal.PostgreSQL.Expression.Inline.InlineParam x ty) => Squeal.PostgreSQL.Expression.Inline.InlineColumn (col Squeal.PostgreSQL.Type.Alias.::: Squeal.PostgreSQL.Expression.Default.Optional Data.SOP.BasicFunctors.I ('Squeal.PostgreSQL.Type.Schema.Def Squeal.PostgreSQL.Type.Schema.:=> x)) (col Squeal.PostgreSQL.Type.Alias.::: ('Squeal.PostgreSQL.Type.Schema.Def Squeal.PostgreSQL.Type.Schema.:=> ty)) instance (Generics.SOP.Record.IsRecord x xs, Data.SOP.Constraint.AllZip Squeal.PostgreSQL.Expression.Inline.InlineField xs (Squeal.PostgreSQL.Type.PG.RowPG x)) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Composite x) instance (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Expression.Inline.InlineParam x ty) => Squeal.PostgreSQL.Expression.Inline.InlineField (alias Squeal.PostgreSQL.Type.Alias.::: x) (alias Squeal.PostgreSQL.Type.Alias.::: ty) instance Squeal.PostgreSQL.Expression.Inline.InlineParam x (Squeal.PostgreSQL.Type.PG.NullPG x) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.VarArray [x]) instance Squeal.PostgreSQL.Expression.Inline.InlineParam x (Squeal.PostgreSQL.Type.PG.NullPG x) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.VarArray (Data.Vector.Vector x)) instance (Squeal.PostgreSQL.Expression.Inline.Inline x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Expression.Inline.InlineParam x ('Squeal.PostgreSQL.Type.Schema.NotNull pg) instance (Squeal.PostgreSQL.Expression.Inline.Inline x, pg Data.Type.Equality.~ Squeal.PostgreSQL.Type.PG.PG x) => Squeal.PostgreSQL.Expression.Inline.InlineParam (GHC.Maybe.Maybe x) ('Squeal.PostgreSQL.Type.Schema.Null pg) instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Bool instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Json x) instance Data.Aeson.Types.ToJSON.ToJSON x => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Jsonb x) instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Char instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Base.String instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Int.Int16 instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Int.Int32 instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Int.Int64 instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Float instance Squeal.PostgreSQL.Expression.Inline.Inline GHC.Types.Double instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Scientific.Scientific instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Text.Internal.Text instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Text.Internal.Lazy.Text instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.VarChar n) instance (GHC.TypeNats.KnownNat n, 1 GHC.TypeNats.<= n) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.FixChar n) instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.Clock.Internal.DiffTime.DiffTime instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.Calendar.Days.Day instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.Clock.Internal.UTCTime.UTCTime instance Squeal.PostgreSQL.Expression.Inline.Inline (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone) instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay instance Squeal.PostgreSQL.Expression.Inline.Inline Data.Time.LocalTime.Internal.LocalTime.LocalTime instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range GHC.Int.Int32) instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range GHC.Int.Int64) instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Scientific.Scientific) instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Time.LocalTime.Internal.LocalTime.LocalTime) instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Time.Clock.Internal.UTCTime.UTCTime) instance Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Expression.Range.Range Data.Time.Calendar.Days.Day) instance Squeal.PostgreSQL.Expression.Inline.Inline Data.UUID.Types.Internal.UUID instance Squeal.PostgreSQL.Expression.Inline.Inline Squeal.PostgreSQL.Type.Money instance Squeal.PostgreSQL.Expression.Inline.Inline Database.PostgreSQL.LibPQ.Oid instance (Generics.SOP.Universe.IsEnumType x, Generics.SOP.Universe.HasDatatypeInfo x) => Squeal.PostgreSQL.Expression.Inline.Inline (Squeal.PostgreSQL.Type.Enumerated x) -- | aggregate functions and arguments module Squeal.PostgreSQL.Expression.Aggregate -- | Aggregate functions compute a single result from a set of input -- values. Aggregate functions can be used as Grouped -- Expressions as well as WindowFunctions. class Aggregate arg expr | expr -> arg -- | A special aggregation that does not require an input -- --
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params from ('NotNull 'PGint8)
-- expression = countStar
-- in printSQL expression
-- :}
-- count(*)
--
countStar :: Aggregate arg expr => expr lat with db params from ( 'NotNull 'PGint8)
-- |
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null ty]] ('NotNull 'PGint8)
-- expression = count (All #col)
-- in printSQL expression
-- :}
-- count(ALL "col")
--
count :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'NotNull 'PGint8)
-- |
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null 'PGnumeric)
-- expression = sum_ (Distinct #col & filterWhere (#col .< 100))
-- in printSQL expression
-- :}
-- sum(DISTINCT "col") FILTER (WHERE ("col" < (100.0 :: numeric)))
--
sum_ :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGSum ty))
-- | input values, including nulls, concatenated into an array
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: 'Null 'PGnumeric]] ('Null ('PGvararray ('Null 'PGnumeric)))
-- expression = arrayAgg (All #col & orderBy [AscNullsFirst #col] & filterWhere (#col .< 100))
-- in printSQL expression
-- :}
-- array_agg(ALL "col" ORDER BY "col" ASC NULLS FIRST) FILTER (WHERE ("col" < (100.0 :: numeric)))
--
arrayAgg :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'Null ( 'PGvararray ty))
-- | aggregates values as a JSON array
jsonAgg :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'Null 'PGjson)
-- | aggregates values as a JSON array
jsonbAgg :: Aggregate arg expr => arg '[ty] lat with db params from -> expr lat with db params from ( 'Null 'PGjsonb)
-- | the bitwise AND of all non-null input values, or null if none
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
-- expression = bitAnd (Distinct #col)
-- in printSQL expression
-- :}
-- bit_and(DISTINCT "col")
--
bitAnd :: (Aggregate arg expr, int `In` PGIntegral) => arg '[null int] lat with db params from -> expr lat with db params from ( 'Null int)
-- | the bitwise OR of all non-null input values, or null if none
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGint4]] ('Null 'PGint4)
-- expression = bitOr (All #col)
-- in printSQL expression
-- :}
-- bit_or(ALL "col")
--
bitOr :: (Aggregate arg expr, int `In` PGIntegral) => arg '[null int] lat with db params from -> expr lat with db params from ( 'Null int)
-- | true if all input values are true, otherwise false
--
--
-- >>> :{
-- let
-- winFun :: WindowFunction 'Ungrouped '[] with db params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
-- winFun = boolAnd (Window #col)
-- in printSQL winFun
-- :}
-- bool_and("col")
--
boolAnd :: Aggregate arg expr => arg '[null 'PGbool] lat with db params from -> expr lat with db params from ( 'Null 'PGbool)
-- | true if at least one input value is true, otherwise false
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
-- expression = boolOr (All #col)
-- in printSQL expression
-- :}
-- bool_or(ALL "col")
--
boolOr :: Aggregate arg expr => arg '[null 'PGbool] lat with db params from -> expr lat with db params from ( 'Null 'PGbool)
-- | equivalent to boolAnd
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped bys) '[] with db params '[tab ::: '["col" ::: null 'PGbool]] ('Null 'PGbool)
-- expression = every (Distinct #col)
-- in printSQL expression
-- :}
-- every(DISTINCT "col")
--
every :: Aggregate arg expr => arg '[null 'PGbool] lat with db params from -> expr lat with db params from ( 'Null 'PGbool)
-- | maximum value of expression across all input values
max_ :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null ty)
-- | minimum value of expression across all input values
min_ :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null ty)
-- | the average (arithmetic mean) of all input values
avg :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | correlation coefficient
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- expression = corr (Alls (#y *: #x))
-- in printSQL expression
-- :}
-- corr(ALL "y", "x")
--
corr :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | population covariance
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- expression = covarPop (Alls (#y *: #x))
-- in printSQL expression
-- :}
-- covar_pop(ALL "y", "x")
--
covarPop :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | sample covariance
--
--
-- >>> :{
-- let
-- winFun :: WindowFunction 'Ungrouped '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- winFun = covarSamp (Windows (#y *: #x))
-- in printSQL winFun
-- :}
-- covar_samp("y", "x")
--
covarSamp :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | average of the independent variable (sum(X)/N)
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- expression = regrAvgX (Alls (#y *: #x))
-- in printSQL expression
-- :}
-- regr_avgx(ALL "y", "x")
--
regrAvgX :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | average of the dependent variable (sum(Y)/N)
--
--
-- >>> :{
-- let
-- winFun :: WindowFunction 'Ungrouped '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- winFun = regrAvgY (Windows (#y *: #x))
-- in printSQL winFun
-- :}
-- regr_avgy("y", "x")
--
regrAvgY :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | number of input rows in which both expressions are nonnull
--
--
-- >>> :{
-- let
-- winFun :: WindowFunction 'Ungrouped '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGint8)
-- winFun = regrCount (Windows (#y *: #x))
-- in printSQL winFun
-- :}
-- regr_count("y", "x")
--
regrCount :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGint8)
-- | y-intercept of the least-squares-fit linear equation determined by the
-- (X, Y) pairs
--
--
-- >>> :{
-- let
-- expression :: Expression ('Grouped g) '[] c s p '[t ::: '["x" ::: 'NotNull 'PGfloat8, "y" ::: 'NotNull 'PGfloat8]] ('Null 'PGfloat8)
-- expression = regrIntercept (Alls (#y *: #x))
-- in printSQL expression
-- :}
-- regr_intercept(ALL "y", "x")
--
regrIntercept :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | regr_r2(Y, X), square of the correlation coefficient
regrR2 :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | regr_slope(Y, X), slope of the least-squares-fit linear
-- equation determined by the (X, Y) pairs
regrSlope :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | regr_sxx(Y, X), sum(X^2) - sum(X)^2/N (“sum of squares” of
-- the independent variable)
regrSxx :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | regr_sxy(Y, X), sum(X*Y) - sum(X) * sum(Y)/N (“sum of
-- products” of independent times dependent variable)
regrSxy :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | regr_syy(Y, X), sum(Y^2) - sum(Y)^2/N (“sum of squares” of
-- the dependent variable)
regrSyy :: Aggregate arg expr => arg '[null 'PGfloat8, null 'PGfloat8] lat with db params from -> expr lat with db params from ( 'Null 'PGfloat8)
-- | historical alias for stddevSamp
stddev :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | population standard deviation of the input values
stddevPop :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | sample standard deviation of the input values
stddevSamp :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | historical alias for varSamp
variance :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | population variance of the input values (square of the population
-- standard deviation)
varPop :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | sample variance of the input values (square of the sample standard
-- deviation)
varSamp :: Aggregate arg expr => arg '[null ty] lat with db params from -> expr lat with db params from ( 'Null (PGAvg ty))
-- | AggregateArgs are used for the input of Aggregate
-- Expressions.
data AggregateArg (xs :: [NullType]) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
AggregateAll :: NP (Expression 'Ungrouped lat with db params from) xs -> [SortExpression 'Ungrouped lat with db params from] -> [Condition 'Ungrouped lat with db params from] -> AggregateArg
[aggregateArgs] :: AggregateArg -> NP (Expression 'Ungrouped lat with db params from) xs
[aggregateOrder] :: AggregateArg -> [SortExpression 'Ungrouped lat with db params from]
[aggregateFilter] :: AggregateArg -> [Condition 'Ungrouped lat with db params from]
AggregateDistinct :: NP (Expression 'Ungrouped lat with db params from) xs -> [SortExpression 'Ungrouped lat with db params from] -> [Condition 'Ungrouped lat with db params from] -> AggregateArg
[aggregateArgs] :: AggregateArg -> NP (Expression 'Ungrouped lat with db params from) xs
[aggregateOrder] :: AggregateArg -> [SortExpression 'Ungrouped lat with db params from]
[aggregateFilter] :: AggregateArg -> [Condition 'Ungrouped lat with db params from]
-- | All invokes the aggregate on a single argument once for each
-- input row.
pattern All :: Expression 'Ungrouped lat with db params from x -> AggregateArg '[x] lat with db params from
-- | All invokes the aggregate on multiple arguments once for each
-- input row.
pattern Alls :: NP (Expression 'Ungrouped lat with db params from) xs -> AggregateArg xs lat with db params from
-- | allNotNull invokes the aggregate on a single argument once for
-- each input row where the argument is not null
allNotNull :: Expression 'Ungrouped lat with db params from ( 'Null x) -> AggregateArg '[ 'NotNull x] lat with db params from
-- | Distinct invokes the aggregate once for each distinct value of
-- the expression found in the input.
pattern Distinct :: Expression 'Ungrouped lat with db params from x -> AggregateArg '[x] lat with db params from
-- | Distincts invokes the aggregate once for each distinct set of
-- values, for multiple expressions, found in the input.
pattern Distincts :: NP (Expression 'Ungrouped lat with db params from) xs -> AggregateArg xs lat with db params from
-- | distinctNotNull invokes the aggregate once for each distinct,
-- not null value of the expression found in the input.
distinctNotNull :: Expression 'Ungrouped lat with db params from ( 'Null x) -> AggregateArg '[ 'NotNull x] lat with db params from
-- | Permits filtering WindowArgs and AggregateArgs
class FilterWhere arg grp | arg -> grp
-- | If filterWhere is specified, then only the input rows for which
-- the Condition evaluates to true are fed to the aggregate
-- function; other rows are discarded.
filterWhere :: FilterWhere arg grp => Condition grp lat with db params from -> arg xs lat with db params from -> arg xs lat with db params from
-- | A type family that calculates PGSum PGType of a given
-- argument PGType.
type family PGSum ty
-- | A type family that calculates PGAvg type of a PGType.
type family PGAvg ty
instance Squeal.PostgreSQL.Expression.Aggregate.Aggregate Squeal.PostgreSQL.Expression.Aggregate.AggregateArg (Squeal.PostgreSQL.Expression.Expression ('Squeal.PostgreSQL.Type.Alias.Grouped bys))
instance Squeal.PostgreSQL.Expression.Aggregate.FilterWhere Squeal.PostgreSQL.Expression.Aggregate.AggregateArg 'Squeal.PostgreSQL.Type.Alias.Ungrouped
instance Data.SOP.Constraint.SListI xs => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Aggregate.AggregateArg xs lat with db params from)
instance Squeal.PostgreSQL.Expression.Sort.OrderBy (Squeal.PostgreSQL.Expression.Aggregate.AggregateArg xs) 'Squeal.PostgreSQL.Type.Alias.Ungrouped
-- | window functions, arguments and definitions
module Squeal.PostgreSQL.Expression.Window
-- | A WindowDefinition is a set of table rows that are somehow
-- related to the current row
data WindowDefinition grp lat with db params from
[WindowDefinition] :: SListI bys => NP (Expression grp lat with db params from) bys -> [SortExpression grp lat with db params from] -> WindowDefinition grp lat with db params from
-- | 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 grp lat with db params from) bys -> WindowDefinition grp lat with db params from
-- | 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 (grp :: Grouping) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType) (ty :: NullType)
UnsafeWindowFunction :: ByteString -> WindowFunction
[renderWindowFunction] :: WindowFunction -> ByteString
-- | WindowArgs are used for the input of WindowFunctions.
data WindowArg (grp :: Grouping) (args :: [NullType]) (lat :: FromType) (with :: FromType) (db :: SchemasType) (params :: [NullType]) (from :: FromType)
WindowArg :: NP (Expression grp lat with db params from) args -> [Condition grp lat with db params from] -> WindowArg
[windowArgs] :: WindowArg -> NP (Expression grp lat with db params from) args
[windowFilter] :: WindowArg -> [Condition grp lat with db params from]
-- | Window invokes a WindowFunction on a single argument.
pattern Window :: Expression grp lat with db params from arg -> WindowArg grp '[arg] lat with db params from
-- | Windows invokes a WindowFunction on multiple argument.
pattern Windows :: NP (Expression grp lat with db params from) args -> WindowArg grp args lat with db params from
-- | A RankNType for window functions with no arguments.
type WinFun0 x = forall grp lat with db params from. WindowFunction grp lat with db params from x " cannot reference aliases"
-- | A RankNType for window functions with 1 argument.
type (-#->) x y = forall grp lat with db params from. WindowArg grp '[x] lat with db params from " input" -> WindowFunction grp lat with db params from y " output"
-- | A RankNType for window functions with a fixed-length list of
-- heterogeneous arguments. Use the *: operator to end your
-- argument lists.
type (--#->) xs y = forall grp lat with db params from. WindowArg grp xs lat with db params from " inputs" -> WindowFunction grp lat with db params from y " output"
-- | 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 (Window 5) -- ntile((5 :: int4)) --ntile :: '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 :: '[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 :: '[ty, 'NotNull 'PGint4, ty] --#-> ty -- | returns value evaluated at the row that is the first row of the window -- frame firstValue :: ty -#-> ty -- | returns value evaluated at the row that is the last row of the window -- frame lastValue :: 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 :: '[null ty, 'NotNull 'PGint4] --#-> 'Null ty -- | escape hatch for defining window functions unsafeWindowFunction1 :: ByteString -> x -#-> y -- | escape hatch for defining multi-argument window functions unsafeWindowFunctionN :: SListI xs => ByteString -> xs --#-> y instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Window.WindowArg grp args lat with db params from) instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty) instance GHC.Classes.Ord (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty) instance GHC.Classes.Eq (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty) instance GHC.Show.Show (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty) instance GHC.Generics.Generic (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty) instance Squeal.PostgreSQL.Expression.Aggregate.Aggregate (Squeal.PostgreSQL.Expression.Window.WindowArg grp) (Squeal.PostgreSQL.Expression.Window.WindowFunction grp) instance Data.SOP.Constraint.SListI args => Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowArg grp args lat with db params from) instance Squeal.PostgreSQL.Expression.Aggregate.FilterWhere (Squeal.PostgreSQL.Expression.Window.WindowArg grp) grp instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowFunction grp lat with db params from ty) instance Squeal.PostgreSQL.Expression.Sort.OrderBy (Squeal.PostgreSQL.Expression.Window.WindowDefinition grp) grp instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Expression.Window.WindowDefinition lat with db from grp params) -- | select statements module Squeal.PostgreSQL.Query.Select -- | the TableExpression in the select command constructs an -- intermediate virtual table by possibly combining tables, views, -- eliminating rows, grouping, etc. This table is finally passed on to -- processing by the select list. The Selection determines which -- columns of the intermediate table are actually output. select :: (SListI row, row ~ (x : xs)) => Selection grp lat with db params from row -> TableExpression grp lat with db params from -> Query lat with db params row -- | Like select but takes an NP list of Expressions -- instead of a general Selection. select_ :: (SListI row, row ~ (x : xs)) => NP (Aliased (Expression grp lat with db params from)) row -> TableExpression grp lat with db params from -> Query lat with db params row -- | After the select list has been processed, the result table can be -- subject to the elimination of duplicate rows using -- selectDistinct. selectDistinct :: (SListI columns, columns ~ (col : cols)) => Selection grp lat with db params from columns -> TableExpression grp lat with db params from -> Query lat with db params columns -- | Like selectDistinct but takes an NP list of -- Expressions instead of a general Selection. selectDistinct_ :: (SListI columns, columns ~ (col : cols)) => NP (Aliased (Expression grp lat with db params from)) columns -> TableExpression grp lat with db params from -> Query lat with db params columns -- | selectDistinctOn keeps only the first row of each set of rows -- where the given expressions evaluate to equal. The DISTINCT ON -- expressions are interpreted using the same rules as for ORDER BY. -- ORDER BY is used to ensure that the desired row appears first. -- -- The DISTINCT ON expression(s) must match the leftmost ORDER BY -- expression(s). The ORDER BY clause will normally contain additional -- expression(s) that determine the desired precedence of rows within -- each DISTINCT ON group. -- -- In order to guarantee they match and reduce redundancy, this function -- will prepend the The DISTINCT ON expressions to the ORDER BY clause. selectDistinctOn :: (SListI columns, columns ~ (col : cols)) => [SortExpression grp lat with db params from] -> Selection grp lat with db params from columns -> TableExpression grp lat with db params from -> Query lat with db params columns -- | Like selectDistinctOn but takes an NP list of -- Expressions instead of a general Selection. selectDistinctOn_ :: (SListI columns, columns ~ (col : cols)) => [SortExpression grp lat with db params from] -> NP (Aliased (Expression grp lat with db params from)) columns -> TableExpression grp lat with db params from -> Query lat with db params columns -- | The simplest kinds of Selection are Star and -- DotStar which emits all columns that a TableExpression -- produces. A select List is a list of Expressions. A -- Selection could be a list of WindowFunctions Over -- WindowDefinition. Additional Selections can be -- selected with Also. data Selection grp lat with db params from row [Star] :: HasUnique tab from row => Selection 'Ungrouped lat with db params from row [DotStar] :: Has tab from row => Alias tab -> Selection 'Ungrouped lat with db params from row [List] :: SListI row => NP (Aliased (Expression grp lat with db params from)) row -> Selection grp lat with db params from row [Over] :: SListI row => NP (Aliased (WindowFunction grp lat with db params from)) row -> WindowDefinition grp lat with db params from -> Selection grp lat with db params from row [Also] :: Selection grp lat with db params from right -> Selection grp lat with db params from left -> Selection grp lat with db params from (Join left right) instance Squeal.PostgreSQL.Type.List.Additional (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from) instance (GHC.TypeLits.KnownSymbol col, row Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.Aliasable col (Squeal.PostgreSQL.Expression.Expression grp lat with db params from ty) (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from row) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Query.Select.Selection 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from row1) instance (Squeal.PostgreSQL.Type.Alias.Has tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty], Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => Squeal.PostgreSQL.Type.Alias.IsQualified tab col (Squeal.PostgreSQL.Query.Select.Selection ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from row1) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty]) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Select.Selection 'Squeal.PostgreSQL.Type.Alias.Ungrouped lat with db params from row1) instance (Squeal.PostgreSQL.Type.Alias.HasUnique tab (Squeal.PostgreSQL.Type.List.Join lat from) row0, Squeal.PostgreSQL.Type.Alias.Has col row0 ty, row1 Data.Type.Equality.~ '[col Squeal.PostgreSQL.Type.Alias.::: ty], Squeal.PostgreSQL.Type.Alias.GroupedBy tab col bys) => GHC.OverloadedLabels.IsLabel col (Squeal.PostgreSQL.Query.Select.Selection ('Squeal.PostgreSQL.Type.Alias.Grouped bys) lat with db params from row1) instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from row) instance Data.String.IsString (Squeal.PostgreSQL.Query.Select.Selection grp lat with db params from '["fromOnly" Squeal.PostgreSQL.Type.Alias.::: 'Squeal.PostgreSQL.Type.Schema.NotNull 'Squeal.PostgreSQL.Type.Schema.PGtext]) -- | data manipulation language module Squeal.PostgreSQL.Manipulation -- | The top level Manipulation_ type is parameterized by a -- db SchemasType, against which the query is -- type-checked, an input params Haskell Type, and an -- ouput row Haskell Type. -- -- Manipulation_ is a type family which resolves into a -- Manipulation, so don't be fooled by the input params and output -- row Haskell Types, which are converted into appropriate -- Postgres [NullType] params and RowType -- rows. Use a top-level Statement to fix actual Haskell input -- params and output rows. -- -- A top-level Manipulation_ can be run using -- manipulateParams, or if params = () using -- manipulate. -- -- Generally, params will be a Haskell tuple or record whose -- entries may be referenced using positional params 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 :: int4), DEFAULT)
--
--
-- out-of-line parameterized insert:
--
--
-- >>> type Columns = '["col1" ::: 'Def :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]
--
-- >>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
--
-- >>> :{
-- let
-- manipulation :: Manipulation_ (Public Schema) (Only Int32) ()
-- manipulation =
-- insertInto_ #tab $ Values_
-- (Default `as` #col1 :* Set (param @1) `as` #col2)
-- in printSQL manipulation
-- :}
-- INSERT INTO "tab" ("col1", "col2") VALUES (DEFAULT, ($1 :: int4))
--
--
-- in-line parameterized insert:
--
--
-- >>> type Columns = '["col1" ::: 'Def :=> 'NotNull 'PGint4, "col2" ::: 'NoDef :=> 'NotNull 'PGint4]
--
-- >>> type Schema = '["tab" ::: 'Table ('[] :=> Columns)]
--
-- >>> :{
-- let
-- manipulation
-- :: Manipulation_ (Public Schema) () ()
-- manipulation =
-- insertInto_ #tab $ inlineValues
-- (Row {col1 = Default , col2 = 2 :: Int32})
-- [Row {col1 = NotDefault (3 :: Int32), col2 = 4 :: Int32}]
-- in printSQL manipulation
-- :}
-- INSERT INTO "tab" ("col1", "col2") VALUES (DEFAULT, (2 :: int4)), ((3 :: int4), (4 :: int4))
--
--
-- returning insert:
--
--
-- >>> :{
-- 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 :: int4), (3 :: int4)) 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' :: text), (E'john@smith.com' :: text)) ON CONFLICT ON CONSTRAINT "uq" DO UPDATE SET "email" = ("excluded"."email" || ((E'; ' :: text) || "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 :: int4) 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_ (db :: 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
--
--
-- >>> :{
-- type Schema = '[
-- "tab" ::: 'Table ('[ "inequality" ::: 'Check '["a","b"]] :=> '[
-- "a" ::: 'NoDef :=> 'NotNull 'PGint4,
-- "b" ::: 'NoDef :=> 'NotNull 'PGint4
-- ])]
-- :}
--
--
--
-- >>> :{
-- let
-- definition :: Definition (Public '[]) (Public Schema)
-- definition = createTable #tab
-- ( (int & notNullable) `as` #a :*
-- (int & notNullable) `as` #b )
-- ( check (#a :* #b) (#a .> #b) `as` #inequality )
-- :}
--
--
--
-- >>> printSQL definition
-- CREATE TABLE "tab" ("a" int NOT NULL, "b" int NOT NULL, CONSTRAINT "inequality" CHECK (("a" > "b")));
--
check :: (Has sch db schema, Has tab schema ( 'Table table), HasAll aliases (TableToRow table) subcolumns) => NP Alias aliases -> (forall t. Condition 'Ungrouped '[] '[] db '[] '[t ::: subcolumns]) -> TableConstraintExpression sch tab db ( '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 db schema, Has tab schema ( 'Table table), HasAll aliases (TableToRow table) subcolumns) => NP Alias aliases -> TableConstraintExpression sch tab db ( '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 db schema, Has tab schema ( 'Table table), HasAll aliases (TableToColumns table) subcolumns, AllNotNull subcolumns) => NP Alias aliases -> TableConstraintExpression sch tab db ( '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 db sch schema child parent table reftable columns refcolumns constraints cols reftys tys => NP Alias columns -> Alias parent -> NP Alias refcolumns -> OnDeleteClause -> OnUpdateClause -> TableConstraintExpression sch child db ( 'ForeignKey columns parent refcolumns)
-- | A constraint synonym between types involved in a foreign key
-- constraint.
type ForeignKeyed db sch schema child parent table reftable columns refcolumns constraints cols reftys tys = (Has sch db schema, Has child schema ( 'Table table), Has parent schema ( 'Table reftable), HasAll columns (TableToColumns table) tys, reftable ~ (constraints :=> cols), HasAll refcolumns cols reftys, 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
instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
instance GHC.Show.Show Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
instance GHC.Classes.Ord Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
instance GHC.Classes.Eq Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
instance GHC.Show.Show Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
instance GHC.Generics.Generic Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.Constraint.OnUpdateClause
instance Control.DeepSeq.NFData Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
instance Squeal.PostgreSQL.Render.RenderSQL Squeal.PostgreSQL.Definition.Constraint.OnDeleteClause
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Constraint.TableConstraintExpression sch tab db constraint)
-- | 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 (db0 :: SchemasType) (db1 :: 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
-- manipulation_.
manipulation_ :: Manipulation '[] db '[] '[] -> Definition db db
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance Control.Category.Category Squeal.PostgreSQL.Definition.Definition
instance (db0 Data.Type.Equality.~ db1) => GHC.Base.Semigroup (Squeal.PostgreSQL.Definition.Definition db0 db1)
instance (db0 Data.Type.Equality.~ db1) => GHC.Base.Monoid (Squeal.PostgreSQL.Definition.Definition db0 db1)
-- | Indexed provides an indexed monad transformer class and a class
-- extending it to run Definitions.
module Squeal.PostgreSQL.Session.Indexed
-- | An Atkey indexed monad is a Functor enriched
-- category. An indexed monad transformer transforms a Monad
-- into an indexed monad, and is a monad transformer when its source and
-- target are the same, enabling use of standard do notation for
-- endo-index operations.
class (forall i j m. Monad m => Functor (t i j m), forall i j m. (i ~ j, Monad m) => Monad (t i j m), forall i j. i ~ j => MonadTrans (t i j)) => IndexedMonadTrans t
-- | indexed analog of <*>
pqAp :: (IndexedMonadTrans t, Monad m) => t i j m (x -> y) -> t j k m x -> t i k m y
-- | indexed analog of join
pqJoin :: (IndexedMonadTrans t, Monad m) => t i j m (t j k m y) -> t i k m y
-- | indexed analog of =<<
pqBind :: (IndexedMonadTrans t, Monad m) => (x -> t j k m y) -> t i j m x -> t i k m y
-- | indexed analog of flipped >>
pqThen :: (IndexedMonadTrans t, Monad m) => t j k m y -> t i j m x -> t i k m y
-- | indexed analog of <=<
pqAndThen :: (IndexedMonadTrans t, Monad m) => (y -> t j k m z) -> (x -> t i j m y) -> x -> t i k m z
-- | Indexed reshuffles the type parameters of an
-- IndexedMonadTrans, exposing its Category instance.
newtype Indexed t m r i j
Indexed :: t i j m r -> Indexed t m r i j
[runIndexed] :: Indexed t m r i j -> t i j m r
-- | IndexedMonadTransPQ is a class for indexed monad transformers
-- that support running Definitions using define which acts
-- functorially in effect.
--
-- define id = return ()
define (statement1 >>> statement2) = define -- statement1 & pqThen (define statement2)
indexedDefine id = id
indexedDefine (def1 >>> def2) = indexedDefine def1 -- >>> indexedDefine def2
-- >>> import Squeal.PostgreSQL ---- --
-- >>> :{
-- do
-- let
-- query :: Query_ (Public '[]) () (Only Char)
-- query = values_ (inline 'a' `as` #fromOnly)
-- pool <- createConnectionPool "host=localhost port=5432 dbname=exampledb" 1 0.5 10
-- chr <- usingConnectionPool pool $ do
-- result <- runQuery query
-- Just (Only a) <- firstRow result
-- return a
-- destroyConnectionPool pool
-- putChar chr
-- :}
-- a
--
module Squeal.PostgreSQL.Session.Pool
type Pool = Pool
-- | Create a striped pool of connections. Although the garbage collector
-- will destroy all idle connections when the pool is garbage collected
-- it's recommended to manually destroyAllResources when you're
-- done with the pool so that the connections are freed up as soon as
-- possible.
createConnectionPool :: forall (db :: SchemasType) io. MonadUnliftIO io => ByteString -> Int -> NominalDiffTime -> Int -> io (Pool (K Connection db))
-- | Temporarily take a connection from a Pool, perform an action
-- with it, and return it to the pool afterwards.
--
-- If the pool has an idle connection available, it is used immediately.
-- Otherwise, if the maximum number of connections has not yet been
-- reached, a new connection is created and used. If the maximum number
-- of connections has been reached, this function blocks until a
-- connection becomes available.
usingConnectionPool :: MonadUnliftIO io => Pool (K Connection db) -> PQ db db io x -> io x
-- | Destroy all connections in all stripes in the pool. Note that this
-- will ignore any exceptions in the destroy function.
--
-- This function is useful when you detect that all connections in the
-- pool are broken. For example after a database has been restarted all
-- connections opened before the restart will be broken. In that case
-- it's better to close those connections so that
-- usingConnectionPool won't take a broken connection from the
-- pool but will open a new connection instead.
--
-- Another use-case for this function is that when you know you are done
-- with the pool you can destroy all idle connections immediately instead
-- of waiting on the garbage collector to destroy them, thus freeing up
-- those connections sooner.
destroyConnectionPool :: MonadUnliftIO io => Pool (K Connection db) -> io ()
-- | create and drop views
module Squeal.PostgreSQL.Definition.View
-- | Create a view.
--
--
-- >>> type ABC = '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4]
--
-- >>> type BC = '["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4]
--
-- >>> :{
-- let
-- definition :: Definition
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC)]]
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC), "bc" ::: 'View BC]]
-- definition =
-- createView #bc (select_ (#b :* #c) (from (table #abc)))
-- in printSQL definition
-- :}
-- CREATE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";
--
createView :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Query '[] '[] db '[] view -> Definition db (Alter sch (Create vw ( 'View view) schema) db)
-- | Create or replace a view.
--
--
-- >>> type ABC = '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4]
--
-- >>> type BC = '["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4]
--
-- >>> :{
-- let
-- definition :: Definition
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC)]]
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> ABC), "bc" ::: 'View BC]]
-- definition =
-- createOrReplaceView #bc (select_ (#b :* #c) (from (table #abc)))
-- in printSQL definition
-- :}
-- CREATE OR REPLACE VIEW "bc" AS SELECT "b" AS "b", "c" AS "c" FROM "abc" AS "abc";
--
createOrReplaceView :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Query '[] '[] db '[] view -> Definition db (Alter sch (CreateOrReplace vw ( 'View view) schema) db)
-- | Drop a view.
--
--
-- >>> :{
-- let
-- definition :: Definition
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])
-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]]
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]]
-- definition = dropView #bc
-- in printSQL definition
-- :}
-- DROP VIEW "bc";
--
dropView :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Definition db (Alter sch (DropSchemum vw 'View schema) db)
-- | Drop a view if it exists.
--
--
-- >>> :{
-- let
-- definition :: Definition
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])
-- , "bc" ::: 'View ('["b" ::: 'Null 'PGint4, "c" ::: 'Null 'PGint4])]]
-- '[ "public" ::: '["abc" ::: 'Table ('[] :=> '["a" ::: 'NoDef :=> 'Null 'PGint4, "b" ::: 'NoDef :=> 'Null 'PGint4, "c" ::: 'NoDef :=> 'Null 'PGint4])]]
-- definition = dropViewIfExists #bc
-- in printSQL definition
-- :}
-- DROP VIEW IF EXISTS "bc";
--
dropViewIfExists :: (Has sch db schema, KnownSymbol vw) => QualifiedAlias sch vw -> Definition db (Alter sch (DropIfExists vw schema) db)
-- | create and drop types
module Squeal.PostgreSQL.Definition.Type
-- | Enumerated types are created using the createTypeEnum command,
-- for example
--
--
-- >>> printSQL $ (createTypeEnum #mood (label @"sad" :* label @"ok" :* label @"happy") :: Definition (Public '[]) '["public" ::: '["mood" ::: 'Typedef ('PGenum '["sad","ok","happy"])]])
-- CREATE TYPE "mood" AS ENUM ('sad', 'ok', 'happy');
--
createTypeEnum :: (KnownSymbol enum, Has sch db schema, All KnownSymbol labels) => QualifiedAlias sch enum -> NP PGlabel labels -> Definition db (Alter sch (Create enum ( 'Typedef ( 'PGenum labels)) schema) db)
-- | Enumerated types can also be generated from a Haskell type, for
-- example
--
--
-- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic
--
-- >>> instance SOP.Generic Schwarma
--
-- >>> instance SOP.HasDatatypeInfo Schwarma
--
-- >>> :{
-- let
-- createSchwarma :: Definition (Public '[]) '["public" ::: '["schwarma" ::: 'Typedef (PG (Enumerated Schwarma))]]
-- createSchwarma = createTypeEnumFrom @Schwarma #schwarma
-- in
-- printSQL createSchwarma
-- :}
-- CREATE TYPE "schwarma" AS ENUM ('Beef', 'Lamb', 'Chicken');
--
createTypeEnumFrom :: forall hask sch enum db schema. (Generic hask, All KnownSymbol (LabelsPG hask), KnownSymbol enum, Has sch db schema) => QualifiedAlias sch enum -> Definition db (Alter sch (Create enum ( 'Typedef (PG (Enumerated hask))) schema) db)
-- | createTypeComposite creates a composite type. The composite
-- type is specified by a list of attribute names and data types.
--
--
-- >>> :{
-- type PGcomplex = 'PGcomposite
-- '[ "real" ::: 'NotNull 'PGfloat8
-- , "imaginary" ::: 'NotNull 'PGfloat8 ]
-- :}
--
--
--
-- >>> :{
-- let
-- setup :: Definition (Public '[]) '["public" ::: '["complex" ::: 'Typedef PGcomplex]]
-- setup = createTypeComposite #complex
-- (float8 `as` #real :* float8 `as` #imaginary)
-- in printSQL setup
-- :}
-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
--
createTypeComposite :: (KnownSymbol ty, Has sch db schema, SListI fields) => QualifiedAlias sch ty -> NP (Aliased (TypeExpression db)) fields -> Definition db (Alter sch (Create ty ( 'Typedef ( 'PGcomposite fields)) schema) db)
-- | Composite types can also be generated from a Haskell type, for example
--
--
-- >>> data Complex = Complex {real :: Double, imaginary :: Double} deriving GHC.Generic
--
-- >>> instance SOP.Generic Complex
--
-- >>> instance SOP.HasDatatypeInfo Complex
--
-- >>> type Schema = '["complex" ::: 'Typedef (PG (Composite Complex))]
--
-- >>> :{
-- let
-- createComplex :: Definition (Public '[]) (Public Schema)
-- createComplex = createTypeCompositeFrom @Complex #complex
-- in
-- printSQL createComplex
-- :}
-- CREATE TYPE "complex" AS ("real" float8, "imaginary" float8);
--
createTypeCompositeFrom :: forall hask sch ty db schema. (All (FieldTyped db) (RowPG hask), KnownSymbol ty, Has sch db schema) => QualifiedAlias sch ty -> Definition db (Alter sch (Create ty ( 'Typedef (PG (Composite hask))) schema) db)
-- | Range types are data types representing a range of values of some
-- element type (called the range's subtype). The subtype must have a
-- total order so that it is well-defined whether element values are
-- within, before, or after a range of values.
--
-- Range types are useful because they represent many element values in a
-- single range value, and because concepts such as overlapping ranges
-- can be expressed clearly. The use of time and date ranges for
-- scheduling purposes is the clearest example; but price ranges,
-- measurement ranges from an instrument, and so forth can also be
-- useful.
--
--
-- >>> :{
-- let
-- createSmallIntRange :: Definition (Public '[]) (Public '["int2range" ::: 'Typedef ('PGrange 'PGint2)])
-- createSmallIntRange = createTypeRange #int2range int2
-- in printSQL createSmallIntRange
-- :}
-- CREATE TYPE "int2range" AS RANGE (subtype = int2);
--
createTypeRange :: (Has sch db schema, KnownSymbol range) => QualifiedAlias sch range -> (forall null. TypeExpression db (null ty)) -> Definition db (Alter sch (Create range ( 'Typedef ( 'PGrange ty)) schema) db)
-- | 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)
-- in printSQL createPositive
-- :}
-- CREATE DOMAIN "positive" AS real CHECK (("value" > (0.0 :: float4)));
--
createDomain :: (Has sch db schema, KnownSymbol dom) => QualifiedAlias sch dom -> (forall null. TypeExpression db (null ty)) -> (forall tab. Condition 'Ungrouped '[] '[] db '[] '[tab ::: '["value" ::: 'Null ty]]) -> Definition db (Alter sch (Create dom ( 'Typedef ty) schema) db)
-- | Drop a type.
--
-- -- >>> data Schwarma = Beef | Lamb | Chicken deriving GHC.Generic -- -- >>> instance SOP.Generic Schwarma -- -- >>> instance SOP.HasDatatypeInfo Schwarma -- -- >>> printSQL (dropType #schwarma :: Definition '["public" ::: '["schwarma" ::: 'Typedef (PG (Enumerated Schwarma))]] (Public '[])) -- DROP TYPE "schwarma"; --dropType :: (Has sch db schema, KnownSymbol td) => QualifiedAlias sch td -> Definition db (Alter sch (DropSchemum td 'Typedef schema) db) -- | Drop a type if it exists. dropTypeIfExists :: (Has sch db schema, KnownSymbol td) => QualifiedAlias sch td -> Definition db (Alter sch (DropSchemumIfExists td 'Typedef schema) db) -- | create, drop and alter tables module Squeal.PostgreSQL.Definition.Table -- | 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 db0 schema0, db1 ~ Alter sch (Create tab ( 'Table (constraints :=> columns)) schema0) db0) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression db0)) columns -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints -> Definition db0 db1
-- | 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 :: (KnownSymbol sch, KnownSymbol tab, columns ~ (col : cols), SListI columns, SListI constraints, Has sch db0 schema0, db1 ~ Alter sch (CreateIfNotExists tab ( 'Table (constraints :=> columns)) schema0) db0) => QualifiedAlias sch tab -> NP (Aliased (ColumnTypeExpression db0)) columns -> NP (Aliased (TableConstraintExpression sch tab db1)) constraints -> Definition db0 db1
-- | dropTable removes a table from the schema.
--
--
-- >>> :{
-- let
-- definition :: Definition '["public" ::: '["muh_table" ::: 'Table t]] (Public '[])
-- definition = dropTable #muh_table
-- :}
--
--
-- -- >>> printSQL definition -- DROP TABLE "muh_table"; --dropTable :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> Definition db (Alter sch (DropSchemum tab 'Table schema) db) -- | Drop a table if it exists. dropTableIfExists :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> Definition db (Alter sch (DropSchemumIfExists tab 'Table schema) db) -- | alterTable changes the definition of a table from the schema. alterTable :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> AlterTable sch tab db table -> Definition db (Alter sch (Alter tab ( 'Table table) schema) db) -- | alterTable changes the definition of a table from the schema. alterTableIfExists :: (Has sch db schema, KnownSymbol tab) => QualifiedAlias sch tab -> AlterTable sch tab db table -> Definition db (Alter sch (AlterIfExists tab ( 'Table table) schema) db) -- | alterTableRename changes the name of a table from the schema. -- --
-- >>> printSQL $ alterTableRename #foo #bar -- ALTER TABLE "foo" RENAME TO "bar"; --alterTableRename :: (KnownSymbol tab0, KnownSymbol tab1) => Alias tab0 -> Alias tab1 -> Definition schema (Rename tab0 tab1 schema) -- | Rename a table if it exists. alterTableIfExistsRename :: (KnownSymbol tab0, KnownSymbol tab1) => Alias tab0 -> Alias tab1 -> Definition schema (RenameIfExists tab0 tab1 schema) -- | An AlterTable describes the alteration to perform on the -- columns of a table. newtype AlterTable (sch :: Symbol) (tab :: Symbol) (db :: 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 :: int4)));
--
addConstraint :: (KnownSymbol alias, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias alias -> TableConstraintExpression sch tab db constraint -> AlterTable sch tab db (Create alias constraint constraints :=> columns)
-- | A dropConstraint drops a table constraint.
--
--
-- >>> :{
-- let
-- definition :: Definition
-- '["public" ::: '["tab" ::: 'Table ('["positive" ::: Check '["col"]] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]
-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4])]]
-- definition = alterTable #tab (dropConstraint #positive)
-- in printSQL definition
-- :}
-- ALTER TABLE "tab" DROP CONSTRAINT "positive";
--
dropConstraint :: (KnownSymbol constraint, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias constraint -> AlterTable sch tab db (Drop constraint constraints :=> columns)
-- | 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' :: text);
--
--
--
-- >>> :{
-- let
-- definition :: Definition
-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]
-- '["public" ::: '["tab" ::: 'Table ('[] :=>
-- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
-- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]]
-- definition = alterTable #tab (addColumn #col2 (text & nullable))
-- in printSQL definition
-- :}
-- ALTER TABLE "tab" ADD COLUMN "col2" text NULL;
--
addColumn :: (AddColumn ty, KnownSymbol column, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias column -> ColumnTypeExpression db ty -> AlterTable sch tab db (constraints :=> Create column ty columns)
-- | A dropColumn removes a column. Whatever data was in the column
-- disappears. Table constraints involving the column are dropped, too.
-- However, if the column is referenced by a foreign key constraint of
-- another table, PostgreSQL will not silently drop that constraint.
--
--
-- >>> :{
-- let
-- definition :: Definition
-- '["public" ::: '["tab" ::: 'Table ('[] :=>
-- '[ "col1" ::: 'NoDef :=> 'Null 'PGint4
-- , "col2" ::: 'NoDef :=> 'Null 'PGtext ])]]
-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["col1" ::: 'NoDef :=> 'Null 'PGint4])]]
-- definition = alterTable #tab (dropColumn #col2)
-- in printSQL definition
-- :}
-- ALTER TABLE "tab" DROP COLUMN "col2";
--
dropColumn :: (KnownSymbol column, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias column -> AlterTable sch tab db (constraints :=> Drop column columns)
-- | A renameColumn renames a column.
--
--
-- >>> :{
-- let
-- definition :: Definition
-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["foo" ::: 'NoDef :=> 'Null 'PGint4])]]
-- '["public" ::: '["tab" ::: 'Table ('[] :=> '["bar" ::: 'NoDef :=> 'Null 'PGint4])]]
-- definition = alterTable #tab (renameColumn #foo #bar)
-- in printSQL definition
-- :}
-- ALTER TABLE "tab" RENAME COLUMN "foo" TO "bar";
--
renameColumn :: (KnownSymbol column0, KnownSymbol column1, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns))) => Alias column0 -> Alias column1 -> AlterTable sch tab db (constraints :=> Rename column0 column1 columns)
-- | An alterColumn alters a single column.
alterColumn :: (KnownSymbol column, Has sch db schema, Has tab schema ( 'Table (constraints :=> columns)), Has column columns ty0) => Alias column -> AlterColumn db ty0 ty1 -> AlterTable sch tab db (constraints :=> Alter column ty1 columns)
-- | An AlterColumn describes the alteration to perform on a single
-- column.
newtype AlterColumn (db :: 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 :: int4);
--
setDefault :: Expression 'Ungrouped '[] '[] db '[] '[] ty -> AlterColumn db (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 db ( '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 db (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 db (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 db ty -> AlterColumn db ty0 ty
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Table.AlterColumn db ty0 ty1)
instance Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
instance GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
instance GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
instance GHC.Show.Show (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
instance GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Table.AlterTable sch tab db table)
instance Squeal.PostgreSQL.Definition.Table.AddColumn ('Squeal.PostgreSQL.Type.Schema.Def Squeal.PostgreSQL.Type.Schema.:=> ty)
instance Squeal.PostgreSQL.Definition.Table.AddColumn ('Squeal.PostgreSQL.Type.Schema.NoDef Squeal.PostgreSQL.Type.Schema.:=> 'Squeal.PostgreSQL.Type.Schema.Null ty)
-- | This module defines a Migration type to safely change the
-- schema of your database over time. Let's see an example!
--
-- First turn on some extensions.
--
-- -- >>> :set -XDataKinds -XOverloadedLabels -- -- >>> :set -XOverloadedStrings -XFlexibleContexts -XTypeOperators ---- -- Next, let's define our 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.
--
-- Migrations are parameterized giving the option of a
--
--
-- >>> :{
-- let
-- makeUsers :: Migration (IsoQ Definition)
-- '["public" ::: '[]]
-- '["public" ::: '["users" ::: 'Table UsersTable]]
-- makeUsers = Migration "make users table" IsoQ
-- { up = createTable #users
-- ( serial `as` #id :*
-- notNullable text `as` #name )
-- ( primaryKey #id `as` #pk_users )
-- , down = dropTable #users
-- }
-- :}
--
--
--
-- >>> :{
-- let
-- makeEmails :: Migration (IsoQ Definition)
-- '["public" ::: '["users" ::: 'Table UsersTable]]
-- '["public" ::: '["users" ::: 'Table UsersTable, "emails" ::: 'Table EmailsTable]]
-- makeEmails = Migration "make emails table" IsoQ
-- { up = createTable #emails
-- ( serial `as` #id :*
-- notNullable int `as` #user_id :*
-- nullable text `as` #email )
-- ( primaryKey #id `as` #pk_emails :*
-- foreignKey #user_id #users #id
-- OnDeleteCascade OnUpdateCascade `as` #fk_user_id )
-- , down = dropTable #emails
-- }
-- :}
--
--
-- Now that we have a couple migrations we can chain them together into a
-- Path.
--
-- -- >>> let migrations = makeUsers :>> makeEmails :>> Done ---- -- Now run the migrations. -- --
-- >>> import Control.Monad.IO.Class
--
-- >>> :{
-- withConnection "host=localhost port=5432 dbname=exampledb" $
-- manipulate_ (UnsafeManipulation "SET client_min_messages TO WARNING;")
-- -- suppress notices
-- & pqThen (liftIO (putStrLn "Migrate"))
-- & pqThen (migrateUp migrations)
-- & pqThen (liftIO (putStrLn "Rollback"))
-- & pqThen (migrateDown migrations)
-- :}
-- Migrate
-- Rollback
--
--
-- We can also create a simple executable using mainMigrateIso.
--
-- -- >>> let main = mainMigrateIso "host=localhost port=5432 dbname=exampledb" migrations ---- --
-- >>> withArgs [] main -- Invalid command: "". Use: -- migrate to run all available migrations -- rollback to rollback all available migrations -- status to display migrations run and migrations left to run ---- --
-- >>> withArgs ["status"] main -- Migrations already run: -- None -- Migrations left to run: -- - make users table -- - make emails table ---- --
-- >>> withArgs ["migrate"] main -- Migrations already run: -- - make users table -- - make emails table -- Migrations left to run: -- None ---- --
-- >>> withArgs ["rollback"] main -- Migrations already run: -- None -- Migrations left to run: -- - make users table -- - make emails table ---- -- In addition to enabling Migrations using pure SQL -- Definitions for the up and down migrations, you -- can also perform impure IO actions by using a Migrations -- over the Indexed PQ IO category. module Squeal.PostgreSQL.Session.Migration -- | A Migration consists of a name and a migration definition. data Migration def db0 db1 Migration :: Text -> def db0 db1 -> Migration def db0 db1 -- | The name of a Migration. Each name in a -- Migration should be unique. [name] :: Migration def db0 db1 -> Text -- | The migration of a Migration. [migration] :: Migration def db0 db1 -> def db0 db1 -- | A Migratory Category can run or possibly rewind a -- Path of Migrations. class (Category def, Category run) => Migratory def run | def -> run -- | Run a Path of Migrations. runMigrations :: Migratory def run => Path (Migration def) db0 db1 -> run db0 db1 -- | Run migrations. migrate :: Migratory def (Indexed PQ IO ()) => Path (Migration def) db0 db1 -> PQ db0 db1 IO () -- | Run rewindable migrations. migrateUp :: Migratory def (IsoQ (Indexed PQ IO ())) => Path (Migration def) db0 db1 -> PQ db0 db1 IO () -- | Rewind migrations. migrateDown :: Migratory def (IsoQ (Indexed PQ IO ())) => Path (Migration def) db0 db1 -> PQ db1 db0 IO () -- | The TableType for a Squeal migration. type MigrationsTable = '["migrations_unique_name" ::: 'Unique '["name"]] :=> '["name" ::: 'NoDef :=> 'NotNull 'PGtext, "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz] -- | mainMigrate creates a simple executable from a connection -- string and a Path of Migrations. mainMigrate :: Migratory p (Indexed PQ IO ()) => ByteString -> Path (Migration p) db0 db1 -> IO () -- | mainMigrateIso creates a simple executable from a connection -- string and a Path of Migration IsoQs. mainMigrateIso :: Migratory (IsoQ def) (IsoQ (Indexed PQ IO ())) => ByteString -> Path (Migration (IsoQ def)) db0 db1 -> IO () -- | Arrows of IsoQ are bidirectional edges. data IsoQ (c :: k -> k -> Type) (x :: k) (y :: k) :: forall k. () => k -> k -> Type -> k -> k -> Type IsoQ :: c x y -> c y x -> IsoQ [up] :: IsoQ -> c x y [down] :: IsoQ -> c y x instance GHC.Show.Show Squeal.PostgreSQL.Session.Migration.MigrationRow instance GHC.Generics.Generic Squeal.PostgreSQL.Session.Migration.MigrationRow instance forall k1 k2 (def :: k1 -> k2 -> *) (db0 :: k1) (db1 :: k2). GHC.Generics.Generic (Squeal.PostgreSQL.Session.Migration.Migration def db0 db1) instance Generics.SOP.Universe.Generic Squeal.PostgreSQL.Session.Migration.MigrationRow instance Generics.SOP.Universe.HasDatatypeInfo Squeal.PostgreSQL.Session.Migration.MigrationRow instance Squeal.PostgreSQL.Session.Migration.Migratory (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()) (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()) instance Squeal.PostgreSQL.Session.Migration.Migratory Squeal.PostgreSQL.Definition.Definition (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ()) instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.OpQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) (Data.Quiver.OpQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.OpQ Squeal.PostgreSQL.Definition.Definition) (Data.Quiver.OpQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.IsoQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) (Data.Quiver.IsoQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) instance Squeal.PostgreSQL.Session.Migration.Migratory (Data.Quiver.IsoQ Squeal.PostgreSQL.Definition.Definition) (Data.Quiver.IsoQ (Squeal.PostgreSQL.Session.Indexed.Indexed Squeal.PostgreSQL.Session.PQ GHC.Types.IO ())) instance Data.Quiver.Functor.QFunctor Squeal.PostgreSQL.Session.Migration.Migration -- | create and drop schemas module Squeal.PostgreSQL.Definition.Schema -- | 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. -- --
-- >>> :{
-- let
-- definition :: Definition '["public" ::: '[]] '["public" ::: '[], "my_schema" ::: '[]]
-- definition = createSchema #my_schema
-- in printSQL definition
-- :}
-- CREATE SCHEMA "my_schema";
--
createSchema :: KnownSymbol sch => Alias sch -> Definition db (Create sch '[] db)
-- | Create a schema if it does not yet exist.
createSchemaIfNotExists :: (KnownSymbol sch, Has sch db schema) => Alias sch -> Definition db (CreateIfNotExists sch '[] db)
-- | Drop a schema. Automatically drop objects (tables, functions, etc.)
-- that are contained in the schema.
--
--
-- >>> :{
-- let
-- definition :: Definition '["muh_schema" ::: schema, "public" ::: public] '["public" ::: public]
-- definition = dropSchemaCascade #muh_schema
-- :}
--
--
-- -- >>> printSQL definition -- DROP SCHEMA "muh_schema" CASCADE; --dropSchemaCascade :: KnownSymbol sch => Alias sch -> Definition db (Drop sch db) -- | Drop a schema if it exists. Automatically drop objects (tables, -- functions, etc.) that are contained in the schema. dropSchemaCascadeIfExists :: KnownSymbol sch => Alias sch -> Definition db (DropIfExists sch db) -- | create and drop indexes module Squeal.PostgreSQL.Definition.Index -- | Create an index. -- --
-- >>> :{
-- type Table = '[] :=>
-- '[ "a" ::: 'NoDef :=> 'Null 'PGint4
-- , "b" ::: 'NoDef :=> 'Null 'PGfloat4 ]
-- :}
--
--
--
-- >>> :{
-- let
-- setup :: Definition (Public '[]) (Public '["tab" ::: 'Table Table, "ix" ::: 'Index 'Btree])
-- setup =
-- createTable #tab (nullable int `as` #a :* nullable real `as` #b) Nil >>>
-- createIndex #ix #tab btree [#a & AscNullsFirst, #b & AscNullsLast]
-- in printSQL setup
-- :}
-- CREATE TABLE "tab" ("a" int NULL, "b" real NULL);
-- CREATE INDEX "ix" ON "tab" USING btree (("a") ASC NULLS FIRST, ("b") ASC NULLS LAST);
--
createIndex :: (Has sch db schema, Has tab schema ( 'Table table), KnownSymbol ix) => Alias ix -> QualifiedAlias sch tab -> IndexMethod method -> [SortExpression 'Ungrouped '[] '[] db '[] '[tab ::: TableToRow table]] -> Definition db (Alter sch (Create ix ( 'Index method) schema) db)
-- | Create an index if it doesn't exist.
createIndexIfNotExists :: (Has sch db schema, Has tab schema ( 'Table table), KnownSymbol ix) => Alias ix -> QualifiedAlias sch tab -> IndexMethod method -> [SortExpression 'Ungrouped '[] '[] db '[] '[tab ::: TableToRow table]] -> Definition db (Alter sch (CreateIfNotExists ix ( 'Index method) schema) db)
-- | Drop an index.
--
-- -- >>> printSQL (dropIndex #ix :: Definition (Public '["ix" ::: 'Index 'Btree]) (Public '[])) -- DROP INDEX "ix"; --dropIndex :: (Has sch db schema, KnownSymbol ix) => QualifiedAlias sch ix -> Definition db (Alter sch (DropSchemum ix 'Index schema) db) -- | Drop an index if it exists. dropIndexIfExists :: (Has sch db schema, KnownSymbol ix) => QualifiedAlias sch ix -> Definition db (Alter sch (DropSchemumIfExists ix 'Index schema) db) -- | PostgreSQL provides several index types: B-tree, Hash, GiST, SP-GiST, -- GIN and BRIN. Each index type uses a different algorithm that is best -- suited to different types of queries. newtype IndexMethod ty UnsafeIndexMethod :: ByteString -> IndexMethod ty [renderIndexMethod] :: IndexMethod ty -> ByteString -- | B-trees can handle equality and range queries on data that can be -- sorted into some ordering. btree :: IndexMethod 'Btree -- | Hash indexes can only handle simple equality comparisons. hash :: IndexMethod 'Hash -- | GiST indexes are not a single kind of index, but rather an -- infrastructure within which many different indexing strategies can be -- implemented. gist :: IndexMethod 'Gist -- | SP-GiST indexes, like GiST indexes, offer an infrastructure that -- supports various kinds of searches. spgist :: IndexMethod 'Spgist -- | GIN indexes are “inverted indexes” which are appropriate for data -- values that contain multiple component values, such as arrays. gin :: IndexMethod 'Gin -- | BRIN indexes (a shorthand for Block Range INdexes) store summaries -- about the values stored in consecutive physical block ranges of a -- table. brin :: IndexMethod 'Brin instance forall k (ty :: k). GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Index.IndexMethod ty) instance forall k (ty :: k). GHC.Show.Show (Squeal.PostgreSQL.Definition.Index.IndexMethod ty) instance forall k (ty :: k). GHC.Classes.Ord (Squeal.PostgreSQL.Definition.Index.IndexMethod ty) instance forall k (ty :: k). GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Index.IndexMethod ty) instance forall k (ty :: k). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Index.IndexMethod ty) -- | create and drop functions module Squeal.PostgreSQL.Definition.Function -- | Create a function. -- --
-- >>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
--
-- >>> :{
-- let
-- definition :: Definition (Public '[]) (Public '["fn" ::: Fn])
-- definition = createFunction #fn (int4 *: int4) int4 $
-- languageSqlExpr (param @1 * param @2 + 1)
-- in printSQL definition
-- :}
-- CREATE FUNCTION "fn" (int4, int4) RETURNS int4 language sql as $$ SELECT * FROM (VALUES (((($1 :: int4) * ($2 :: int4)) + (1 :: int4)))) AS t ("ret") $$;
--
createFunction :: (Has sch db schema, KnownSymbol fun, SListI args) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> TypeExpression db ret -> FunctionDefinition db args ( 'Returns ret) -> Definition db (Alter sch (Create fun ( 'Function (args :=> 'Returns ret)) schema) db)
-- | Create or replace a function. It is not possible to change the name or
-- argument types or return type of a function this way.
--
--
-- >>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
--
-- >>> :{
-- let
-- definition :: Definition (Public '["fn" ::: Fn]) (Public '["fn" ::: Fn])
-- definition =
-- createOrReplaceFunction #fn
-- (int4 *: int4) int4 $
-- languageSqlExpr (param @1 @('Null 'PGint4) * param @2 @('Null 'PGint4) + 1)
-- in printSQL definition
-- :}
-- CREATE OR REPLACE FUNCTION "fn" (int4, int4) RETURNS int4 language sql as $$ SELECT * FROM (VALUES (((($1 :: int4) * ($2 :: int4)) + (1 :: int4)))) AS t ("ret") $$;
--
createOrReplaceFunction :: (Has sch db schema, KnownSymbol fun, SListI args) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> TypeExpression db ret -> FunctionDefinition db args ( 'Returns ret) -> Definition db (Alter sch (CreateOrReplace fun ( 'Function (args :=> 'Returns ret)) schema) db)
-- | Create a set function.
--
--
-- >>> type Tab = 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])
--
-- >>> type Fn = 'Function ('[ 'Null 'PGint4, 'Null 'PGint4] :=> 'ReturnsTable '["ret" ::: 'Null 'PGint4])
--
-- >>> :{
-- let
-- definition :: Definition (Public '["tab" ::: Tab]) (Public '["tab" ::: Tab, "fn" ::: Fn])
-- definition = createSetFunction #fn (int4 *: int4) (int4 `as` #ret) $
-- languageSqlQuery (select_ ((param @1 * param @2 + #col) `as` #ret) (from (table #tab)))
-- in printSQL definition
-- :}
-- CREATE FUNCTION "fn" (int4, int4) RETURNS TABLE ("ret" int4) language sql as $$ SELECT ((($1 :: int4) * ($2 :: int4)) + "col") AS "ret" FROM "tab" AS "tab" $$;
--
createSetFunction :: (Has sch db schema, KnownSymbol fun, SListI args, SListI rets) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> NP (Aliased (TypeExpression db)) rets -> FunctionDefinition db args ( 'ReturnsTable rets) -> Definition db (Alter sch (Create fun ( 'Function (args :=> 'ReturnsTable rets)) schema) db)
-- | Create or replace a set function.
--
--
-- >>> type Tab = 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])
--
-- >>> type Fn = 'Function ('[ 'Null 'PGint4, 'Null 'PGint4] :=> 'ReturnsTable '["ret" ::: 'Null 'PGint4])
--
-- >>> :{
-- let
-- definition :: Definition (Public '["tab" ::: Tab, "fn" ::: Fn]) (Public '["tab" ::: Tab, "fn" ::: Fn])
-- definition = createOrReplaceSetFunction #fn (int4 *: int4) (int4 `as` #ret) $
-- languageSqlQuery (select_ ((param @1 * param @2 + #col) `as` #ret) (from (table #tab)))
-- in printSQL definition
-- :}
-- CREATE OR REPLACE FUNCTION "fn" (int4, int4) RETURNS TABLE ("ret" int4) language sql as $$ SELECT ((($1 :: int4) * ($2 :: int4)) + "col") AS "ret" FROM "tab" AS "tab" $$;
--
createOrReplaceSetFunction :: (Has sch db schema, KnownSymbol fun, SListI args, SListI rets) => QualifiedAlias sch fun -> NP (TypeExpression db) args -> NP (Aliased (TypeExpression db)) rets -> FunctionDefinition db args ( 'ReturnsTable rets) -> Definition db (Alter sch (CreateOrReplace fun ( 'Function (args :=> 'ReturnsTable rets)) schema) db)
-- | Drop a function.
--
--
-- >>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
--
-- >>> :{
-- let
-- definition :: Definition (Public '["fn" ::: Fn]) (Public '[])
-- definition = dropFunction #fn
-- in printSQL definition
-- :}
-- DROP FUNCTION "fn";
--
dropFunction :: (Has sch db schema, KnownSymbol fun) => QualifiedAlias sch fun -> Definition db (Alter sch (DropSchemum fun 'Function schema) db)
-- | Drop a function.
--
--
-- >>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
--
-- >>> :{
-- let
-- definition :: Definition (Public '[]) (Public '[])
-- definition = dropFunctionIfExists #fn
-- in printSQL definition
-- :}
-- DROP FUNCTION IF EXISTS "fn";
--
dropFunctionIfExists :: (Has sch db schema, KnownSymbol fun) => QualifiedAlias sch fun -> Definition db (Alter sch (DropSchemumIfExists fun 'Function schema) db)
-- | Body of a user defined function
newtype FunctionDefinition db args ret
UnsafeFunctionDefinition :: ByteString -> FunctionDefinition db args ret
[renderFunctionDefinition] :: FunctionDefinition db args ret -> ByteString
-- | Use a parameterized Expression as a function body
languageSqlExpr :: Expression 'Ungrouped '[] '[] db args '[] ret -> FunctionDefinition db args ( 'Returns ret)
-- | Use a parametrized Query as a function body
languageSqlQuery :: Query '[] '[] db args rets -> FunctionDefinition db args ( 'ReturnsTable rets)
instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). Control.DeepSeq.NFData (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). GHC.Generics.Generic (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). GHC.Show.Show (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
instance forall k1 (db :: k1) k2 (args :: k2) k3 (ret :: k3). GHC.Classes.Eq (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
instance forall k1 k2 k3 (db :: k3) (args :: k2) (ret :: k1). Squeal.PostgreSQL.Render.RenderSQL (Squeal.PostgreSQL.Definition.Function.FunctionDefinition db args ret)
-- | 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 DB = 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 an
-- Optionality with a NullType, 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 '[]) DB
-- 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 DB. 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 DB (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. -- --
-- >>> :set -XDerivingStrategies -XDeriveAnyClass
--
-- >>> :{
-- data User = User { userName :: Text, userEmail :: Maybe Text }
-- deriving stock (Show, GHC.Generic)
-- deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
-- :}
--
--
-- Next, we'll write Statements to insert Users into our
-- two tables. A Statement has three type parameters, the schemas
-- it refers to, input parameters and an output row. When we insert into
-- the users table, we will need a parameter for the name field
-- but not for the id field. Since it's serial, we can use a
-- default value. However, since the emails table refers to the users
-- table, we will need to retrieve the user id that the insert generates
-- and insert it into the emails table. We can do this in a single
-- Statement by using a with manipulation.
--
--
-- >>> :{
-- let
-- insertUser :: Statement DB User ()
-- insertUser = manipulation $ 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 Statement to retrieve users from the database.
-- We're not interested in the ids here, just the usernames and email
-- addresses. We need to use an innerJoin to get the right result.
--
--
-- >>> :{
-- let
-- getUsers :: Statement DB () User
-- getUsers = query $ select_
-- (#u ! #name `as` #userName :* #e ! #email `as` #userEmail)
-- ( from (table (#users `as` #u)
-- & innerJoin (table (#emails `as` #e))
-- (#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 DB DB IO ()
-- session = do
-- executePrepared_ insertUser users
-- usersResult <- execute getUsers
-- usersRows <- getRows usersResult
-- liftIO $ print usersRows
-- 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 ()