{-|
Module: Squeal.PostgreSQL.Definition.Function
Description: create and drop functions
Copyright: (c) Eitan Chatav, 2019
Maintainer: eitan@morphism.tech
Stability: experimental

create and drop functions
-}

{-# LANGUAGE
    AllowAmbiguousTypes
  , ConstraintKinds
  , DeriveAnyClass
  , DeriveGeneric
  , DerivingStrategies
  , FlexibleContexts
  , FlexibleInstances
  , GADTs
  , LambdaCase
  , MultiParamTypeClasses
  , OverloadedLabels
  , OverloadedStrings
  , RankNTypes
  , ScopedTypeVariables
  , TypeApplications
  , TypeInType
  , TypeOperators
  , UndecidableSuperClasses
#-}

module Squeal.PostgreSQL.Definition.Function
  ( -- * Create
    createFunction
  , createOrReplaceFunction
  , createSetFunction
  , createOrReplaceSetFunction
    -- * Drop
  , dropFunction
  , dropFunctionIfExists
    -- * Function Definition
  , FunctionDefinition(..)
  , languageSqlExpr
  , languageSqlQuery
  ) where

import Control.DeepSeq
import Data.ByteString
import GHC.TypeLits

import qualified Generics.SOP as SOP
import qualified GHC.Generics as GHC

import Squeal.PostgreSQL.Type.Alias
import Squeal.PostgreSQL.Definition
import Squeal.PostgreSQL.Expression
import Squeal.PostgreSQL.Expression.Type
import Squeal.PostgreSQL.Type.List
import Squeal.PostgreSQL.Query
import Squeal.PostgreSQL.Query.Values
import Squeal.PostgreSQL.Render
import Squeal.PostgreSQL.Type.Schema

-- $setup
-- >>> import Squeal.PostgreSQL

{- | Create a function.

>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
>>> :{
let
  definition :: Definition (Public '[]) (Public '["fn" ::: Fn])
  definition = createFunction #fn (int4 *: int4) int4 $
    languageSqlExpr (param @1 * param @2 + 1)
in printSQL definition
:}
CREATE FUNCTION "fn" (int4, int4) RETURNS int4 language sql as $$ SELECT * FROM (VALUES (((($1 :: int4) * ($2 :: int4)) + (1 :: int4)))) AS t ("ret") $$;
-}
createFunction
  :: ( Has sch db schema
     , KnownSymbol fun
     , SOP.SListI args )
  => QualifiedAlias sch fun -- ^ function alias
  -> NP (TypeExpression db) args -- ^ arguments
  -> TypeExpression db ret -- ^ return type
  -> FunctionDefinition db args ('Returns ret) -- ^ function definition
  -> Definition db (Alter sch (Create fun ('Function (args :=> 'Returns ret)) schema) db)
createFunction :: 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)
createFunction QualifiedAlias sch fun
fun NP (TypeExpression db) args
args TypeExpression db ret
ret FunctionDefinition db args ('Returns ret)
fundef = ByteString
-> Definition
     db
     (Alter
        sch (Create fun ('Function (args :=> 'Returns ret)) schema) db)
forall (db0 :: [(Symbol, SchemaType)])
       (db1 :: [(Symbol, SchemaType)]).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString
 -> Definition
      db
      (Alter
         sch (Create fun ('Function (args :=> 'Returns ret)) schema) db))
-> ByteString
-> Definition
     db
     (Alter
        sch (Create fun ('Function (args :=> 'Returns ret)) schema) db)
forall a b. (a -> b) -> a -> b
$
  ByteString
"CREATE" ByteString -> ByteString -> ByteString
<+> ByteString
"FUNCTION" ByteString -> ByteString -> ByteString
<+> QualifiedAlias sch fun -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL QualifiedAlias sch fun
fun
    ByteString -> ByteString -> ByteString
<+> ByteString -> ByteString
parenthesized ((forall (x :: NullType). TypeExpression db x -> ByteString)
-> NP (TypeExpression db) args -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall sql. RenderSQL sql => sql -> ByteString
forall (x :: NullType). TypeExpression db x -> ByteString
renderSQL NP (TypeExpression db) args
args)
    ByteString -> ByteString -> ByteString
<+> ByteString
"RETURNS" ByteString -> ByteString -> ByteString
<+> TypeExpression db ret -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL TypeExpression db ret
ret ByteString -> ByteString -> ByteString
<+> FunctionDefinition db args ('Returns ret) -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FunctionDefinition db args ('Returns ret)
fundef ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"

{- | Create or replace a function.
It is not possible to change the name or argument types
or return type of a function this way.

>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
>>> :{
let
  definition :: Definition (Public '["fn" ::: Fn]) (Public '["fn" ::: Fn])
  definition =
    createOrReplaceFunction #fn
      (int4 *: int4) int4 $
      languageSqlExpr (param @1 @('Null 'PGint4) * param @2 @('Null 'PGint4) + 1)
in printSQL definition
:}
CREATE OR REPLACE FUNCTION "fn" (int4, int4) RETURNS int4 language sql as $$ SELECT * FROM (VALUES (((($1 :: int4) * ($2 :: int4)) + (1 :: int4)))) AS t ("ret") $$;
-}
createOrReplaceFunction
  :: ( Has sch db schema
     , KnownSymbol fun
     , SOP.SListI args )
  => QualifiedAlias sch fun -- ^ function alias
  -> NP (TypeExpression db) args -- ^ arguments
  -> TypeExpression db ret -- ^ return type
  -> FunctionDefinition db args ('Returns ret) -- ^ function definition
  -> Definition db (Alter sch (CreateOrReplace fun ('Function (args :=> 'Returns ret)) schema) db)
createOrReplaceFunction :: 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)
createOrReplaceFunction QualifiedAlias sch fun
fun NP (TypeExpression db) args
args TypeExpression db ret
ret FunctionDefinition db args ('Returns ret)
fundef = ByteString
-> Definition
     db
     (Alter
        sch
        (CreateOrReplace fun ('Function (args :=> 'Returns ret)) schema)
        db)
forall (db0 :: [(Symbol, SchemaType)])
       (db1 :: [(Symbol, SchemaType)]).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString
 -> Definition
      db
      (Alter
         sch
         (CreateOrReplace fun ('Function (args :=> 'Returns ret)) schema)
         db))
-> ByteString
-> Definition
     db
     (Alter
        sch
        (CreateOrReplace fun ('Function (args :=> 'Returns ret)) schema)
        db)
forall a b. (a -> b) -> a -> b
$
  ByteString
"CREATE" ByteString -> ByteString -> ByteString
<+> ByteString
"OR" ByteString -> ByteString -> ByteString
<+> ByteString
"REPLACE" ByteString -> ByteString -> ByteString
<+> ByteString
"FUNCTION" ByteString -> ByteString -> ByteString
<+> QualifiedAlias sch fun -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL QualifiedAlias sch fun
fun
    ByteString -> ByteString -> ByteString
<+> ByteString -> ByteString
parenthesized ((forall (x :: NullType). TypeExpression db x -> ByteString)
-> NP (TypeExpression db) args -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall sql. RenderSQL sql => sql -> ByteString
forall (x :: NullType). TypeExpression db x -> ByteString
renderSQL NP (TypeExpression db) args
args)
    ByteString -> ByteString -> ByteString
<+> ByteString
"RETURNS" ByteString -> ByteString -> ByteString
<+> TypeExpression db ret -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL TypeExpression db ret
ret ByteString -> ByteString -> ByteString
<+> FunctionDefinition db args ('Returns ret) -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FunctionDefinition db args ('Returns ret)
fundef ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"

-- | Use a parameterized `Expression` as a function body
languageSqlExpr
  :: Expression 'Ungrouped '[] '[] db args '[] ret
  -- ^ function body
  -> FunctionDefinition db args ('Returns ret)
languageSqlExpr :: Expression 'Ungrouped '[] '[] db args '[] ret
-> FunctionDefinition db args ('Returns ret)
languageSqlExpr Expression 'Ungrouped '[] '[] db args '[] ret
expr = ByteString -> FunctionDefinition db args ('Returns ret)
forall k k k (db :: k) (args :: k) (ret :: k).
ByteString -> FunctionDefinition db args ret
UnsafeFunctionDefinition (ByteString -> FunctionDefinition db args ('Returns ret))
-> ByteString -> FunctionDefinition db args ('Returns ret)
forall a b. (a -> b) -> a -> b
$
  ByteString
"language sql as"
    ByteString -> ByteString -> ByteString
<+> ByteString
"$$" ByteString -> ByteString -> ByteString
<+> Query '[] '[] db args '["ret" ::: ret] -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL (NP
  (Aliased (Expression 'Ungrouped '[] '[] db args '[]))
  '["ret" ::: ret]
-> Query '[] '[] db args '["ret" ::: ret]
forall (cols :: RowType) (lat :: FromType) (with :: FromType)
       (db :: [(Symbol, SchemaType)]) (params :: [NullType]).
SListI cols =>
NP (Aliased (Expression 'Ungrouped lat with db params '[])) cols
-> Query lat with db params cols
values_ (Expression 'Ungrouped '[] '[] db args '[] ret
expr `as` IsLabel "ret" (Alias "ret")
Alias "ret"
#ret)) ByteString -> ByteString -> ByteString
<+> ByteString
"$$"

-- | Use a parametrized `Query` as a function body
languageSqlQuery
  :: Query '[] '[] db args rets
  -- ^ function body
  -> FunctionDefinition db args ('ReturnsTable rets)
languageSqlQuery :: Query '[] '[] db args rets
-> FunctionDefinition db args ('ReturnsTable rets)
languageSqlQuery Query '[] '[] db args rets
qry = ByteString -> FunctionDefinition db args ('ReturnsTable rets)
forall k k k (db :: k) (args :: k) (ret :: k).
ByteString -> FunctionDefinition db args ret
UnsafeFunctionDefinition (ByteString -> FunctionDefinition db args ('ReturnsTable rets))
-> ByteString -> FunctionDefinition db args ('ReturnsTable rets)
forall a b. (a -> b) -> a -> b
$
  ByteString
"language sql as" ByteString -> ByteString -> ByteString
<+> ByteString
"$$" ByteString -> ByteString -> ByteString
<+> Query '[] '[] db args rets -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Query '[] '[] db args rets
qry ByteString -> ByteString -> ByteString
<+> ByteString
"$$"

{- | Create a set function.

>>> type Tab = 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])
>>> type Fn = 'Function ('[ 'Null 'PGint4, 'Null 'PGint4] :=> 'ReturnsTable '["ret" ::: 'Null 'PGint4])
>>> :{
let
  definition :: Definition (Public '["tab" ::: Tab]) (Public '["tab" ::: Tab, "fn" ::: Fn])
  definition = createSetFunction #fn (int4 *: int4) (int4 `as` #ret) $
    languageSqlQuery (select_ ((param @1 * param @2 + #col) `as` #ret) (from (table #tab)))
in printSQL definition
:}
CREATE FUNCTION "fn" (int4, int4) RETURNS TABLE ("ret" int4) language sql as $$ SELECT ((($1 :: int4) * ($2 :: int4)) + "col") AS "ret" FROM "tab" AS "tab" $$;
-}
createSetFunction
  :: ( Has sch db schema
     , KnownSymbol fun
     , SOP.SListI args
     , SOP.SListI rets )
  => QualifiedAlias sch fun -- ^ function alias
  -> NP (TypeExpression db) args -- ^ arguments
  -> NP (Aliased (TypeExpression db)) rets -- ^ return type
  -> FunctionDefinition db args ('ReturnsTable rets) -- ^ function definition
  -> Definition db (Alter sch (Create fun ('Function (args :=> 'ReturnsTable rets)) schema) db)
createSetFunction :: 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)
createSetFunction QualifiedAlias sch fun
fun NP (TypeExpression db) args
args NP (Aliased (TypeExpression db)) rets
rets FunctionDefinition db args ('ReturnsTable rets)
fundef = ByteString
-> Definition
     db
     (Alter
        sch
        (Create fun ('Function (args :=> 'ReturnsTable rets)) schema)
        db)
forall (db0 :: [(Symbol, SchemaType)])
       (db1 :: [(Symbol, SchemaType)]).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString
 -> Definition
      db
      (Alter
         sch
         (Create fun ('Function (args :=> 'ReturnsTable rets)) schema)
         db))
-> ByteString
-> Definition
     db
     (Alter
        sch
        (Create fun ('Function (args :=> 'ReturnsTable rets)) schema)
        db)
forall a b. (a -> b) -> a -> b
$
  ByteString
"CREATE" ByteString -> ByteString -> ByteString
<+> ByteString
"FUNCTION" ByteString -> ByteString -> ByteString
<+> QualifiedAlias sch fun -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL QualifiedAlias sch fun
fun
    ByteString -> ByteString -> ByteString
<+> ByteString -> ByteString
parenthesized ((forall (x :: NullType). TypeExpression db x -> ByteString)
-> NP (TypeExpression db) args -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall sql. RenderSQL sql => sql -> ByteString
forall (x :: NullType). TypeExpression db x -> ByteString
renderSQL NP (TypeExpression db) args
args)
    ByteString -> ByteString -> ByteString
<+> ByteString
"RETURNS" ByteString -> ByteString -> ByteString
<+> ByteString
"TABLE"
    ByteString -> ByteString -> ByteString
<+> ByteString -> ByteString
parenthesized ((forall (x :: (Symbol, NullType)).
 Aliased (TypeExpression db) x -> ByteString)
-> NP (Aliased (TypeExpression db)) rets -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall (s :: [(Symbol, SchemaType)]) (r :: (Symbol, NullType)).
Aliased (TypeExpression s) r -> ByteString
forall (x :: (Symbol, NullType)).
Aliased (TypeExpression db) x -> ByteString
renderRet NP (Aliased (TypeExpression db)) rets
rets)
    ByteString -> ByteString -> ByteString
<+> FunctionDefinition db args ('ReturnsTable rets) -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FunctionDefinition db args ('ReturnsTable rets)
fundef ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"
  where
    renderRet :: Aliased (TypeExpression s) r -> ByteString
    renderRet :: Aliased (TypeExpression s) r -> ByteString
renderRet (TypeExpression s ty
ty `As` Alias alias
col) = Alias alias -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Alias alias
col ByteString -> ByteString -> ByteString
<+> TypeExpression s ty -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL TypeExpression s ty
ty

{- | Create or replace a set function.

>>> type Tab = 'Table ('[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4])
>>> type Fn = 'Function ('[ 'Null 'PGint4, 'Null 'PGint4] :=> 'ReturnsTable '["ret" ::: 'Null 'PGint4])
>>> :{
let
  definition :: Definition (Public '["tab" ::: Tab, "fn" ::: Fn]) (Public '["tab" ::: Tab, "fn" ::: Fn])
  definition = createOrReplaceSetFunction #fn (int4 *: int4) (int4 `as` #ret) $
    languageSqlQuery (select_ ((param @1 * param @2 + #col) `as` #ret) (from (table #tab)))
in printSQL definition
:}
CREATE OR REPLACE FUNCTION "fn" (int4, int4) RETURNS TABLE ("ret" int4) language sql as $$ SELECT ((($1 :: int4) * ($2 :: int4)) + "col") AS "ret" FROM "tab" AS "tab" $$;
-}
createOrReplaceSetFunction
  :: ( Has sch db schema
     , KnownSymbol fun
     , SOP.SListI args
     , SOP.SListI rets )
  => QualifiedAlias sch fun -- ^ function alias
  -> NP (TypeExpression db) args -- ^ arguments
  -> NP (Aliased (TypeExpression db)) rets -- ^ return type
  -> FunctionDefinition db args ('ReturnsTable rets) -- ^ function definition
  -> Definition db (Alter sch (CreateOrReplace fun ('Function (args :=> 'ReturnsTable rets)) schema) db)
createOrReplaceSetFunction :: 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)
createOrReplaceSetFunction QualifiedAlias sch fun
fun NP (TypeExpression db) args
args NP (Aliased (TypeExpression db)) rets
rets FunctionDefinition db args ('ReturnsTable rets)
fundef = ByteString
-> Definition
     db
     (Alter
        sch
        (CreateOrReplace
           fun ('Function (args :=> 'ReturnsTable rets)) schema)
        db)
forall (db0 :: [(Symbol, SchemaType)])
       (db1 :: [(Symbol, SchemaType)]).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString
 -> Definition
      db
      (Alter
         sch
         (CreateOrReplace
            fun ('Function (args :=> 'ReturnsTable rets)) schema)
         db))
-> ByteString
-> Definition
     db
     (Alter
        sch
        (CreateOrReplace
           fun ('Function (args :=> 'ReturnsTable rets)) schema)
        db)
forall a b. (a -> b) -> a -> b
$
  ByteString
"CREATE" ByteString -> ByteString -> ByteString
<+> ByteString
"OR" ByteString -> ByteString -> ByteString
<+> ByteString
"REPLACE" ByteString -> ByteString -> ByteString
<+> ByteString
"FUNCTION" ByteString -> ByteString -> ByteString
<+> QualifiedAlias sch fun -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL QualifiedAlias sch fun
fun
    ByteString -> ByteString -> ByteString
<+> ByteString -> ByteString
parenthesized ((forall (x :: NullType). TypeExpression db x -> ByteString)
-> NP (TypeExpression db) args -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall sql. RenderSQL sql => sql -> ByteString
forall (x :: NullType). TypeExpression db x -> ByteString
renderSQL NP (TypeExpression db) args
args)
    ByteString -> ByteString -> ByteString
<+> ByteString
"RETURNS" ByteString -> ByteString -> ByteString
<+> ByteString
"TABLE"
    ByteString -> ByteString -> ByteString
<+> ByteString -> ByteString
parenthesized ((forall (x :: (Symbol, NullType)).
 Aliased (TypeExpression db) x -> ByteString)
-> NP (Aliased (TypeExpression db)) rets -> ByteString
forall k (xs :: [k]) (expression :: k -> *).
SListI xs =>
(forall (x :: k). expression x -> ByteString)
-> NP expression xs -> ByteString
renderCommaSeparated forall (s :: [(Symbol, SchemaType)]) (r :: (Symbol, NullType)).
Aliased (TypeExpression s) r -> ByteString
forall (x :: (Symbol, NullType)).
Aliased (TypeExpression db) x -> ByteString
renderRet NP (Aliased (TypeExpression db)) rets
rets)
    ByteString -> ByteString -> ByteString
<+> FunctionDefinition db args ('ReturnsTable rets) -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL FunctionDefinition db args ('ReturnsTable rets)
fundef ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"
  where
    renderRet :: Aliased (TypeExpression s) r -> ByteString
    renderRet :: Aliased (TypeExpression s) r -> ByteString
renderRet (TypeExpression s ty
ty `As` Alias alias
col) = Alias alias -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL Alias alias
col ByteString -> ByteString -> ByteString
<+> TypeExpression s ty -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL TypeExpression s ty
ty

{- | Drop a function.

>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
>>> :{
let
  definition :: Definition (Public '["fn" ::: Fn]) (Public '[])
  definition = dropFunction #fn
in printSQL definition
:}
DROP FUNCTION "fn";
-}
dropFunction
  :: (Has sch db schema, KnownSymbol fun)
  => QualifiedAlias sch fun
  -- ^ function alias
  -> Definition db (Alter sch (DropSchemum fun 'Function schema) db)
dropFunction :: QualifiedAlias sch fun
-> Definition db (Alter sch (DropSchemum fun 'Function schema) db)
dropFunction QualifiedAlias sch fun
fun = ByteString
-> Definition db (Alter sch (DropSchemum fun 'Function schema) db)
forall (db0 :: [(Symbol, SchemaType)])
       (db1 :: [(Symbol, SchemaType)]).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString
 -> Definition db (Alter sch (DropSchemum fun 'Function schema) db))
-> ByteString
-> Definition db (Alter sch (DropSchemum fun 'Function schema) db)
forall a b. (a -> b) -> a -> b
$
  ByteString
"DROP FUNCTION" ByteString -> ByteString -> ByteString
<+> QualifiedAlias sch fun -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL QualifiedAlias sch fun
fun ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"

{- | Drop a function.

>>> type Fn = 'Function ( '[ 'Null 'PGint4, 'Null 'PGint4] :=> 'Returns ( 'Null 'PGint4))
>>> :{
let
  definition :: Definition (Public '[]) (Public '[])
  definition = dropFunctionIfExists #fn
in printSQL definition
:}
DROP FUNCTION IF EXISTS "fn";
-}
dropFunctionIfExists
  :: (Has sch db schema, KnownSymbol fun)
  => QualifiedAlias sch fun
  -- ^ function alias
  -> Definition db (Alter sch (DropSchemumIfExists fun 'Function schema) db)
dropFunctionIfExists :: QualifiedAlias sch fun
-> Definition
     db (Alter sch (DropSchemumIfExists fun 'Function schema) db)
dropFunctionIfExists QualifiedAlias sch fun
fun = ByteString
-> Definition
     db (Alter sch (DropSchemumIfExists fun 'Function schema) db)
forall (db0 :: [(Symbol, SchemaType)])
       (db1 :: [(Symbol, SchemaType)]).
ByteString -> Definition db0 db1
UnsafeDefinition (ByteString
 -> Definition
      db (Alter sch (DropSchemumIfExists fun 'Function schema) db))
-> ByteString
-> Definition
     db (Alter sch (DropSchemumIfExists fun 'Function schema) db)
forall a b. (a -> b) -> a -> b
$
  ByteString
"DROP FUNCTION IF EXISTS" ByteString -> ByteString -> ByteString
<+> QualifiedAlias sch fun -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL QualifiedAlias sch fun
fun ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"

{- | Body of a user defined function-}
newtype FunctionDefinition db args ret = UnsafeFunctionDefinition
  { FunctionDefinition db args ret -> ByteString
renderFunctionDefinition :: ByteString }
  deriving (FunctionDefinition db args ret
-> FunctionDefinition db args ret -> Bool
(FunctionDefinition db args ret
 -> FunctionDefinition db args ret -> Bool)
-> (FunctionDefinition db args ret
    -> FunctionDefinition db args ret -> Bool)
-> Eq (FunctionDefinition db args ret)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret
-> FunctionDefinition db args ret -> Bool
/= :: FunctionDefinition db args ret
-> FunctionDefinition db args ret -> Bool
$c/= :: forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret
-> FunctionDefinition db args ret -> Bool
== :: FunctionDefinition db args ret
-> FunctionDefinition db args ret -> Bool
$c== :: forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret
-> FunctionDefinition db args ret -> Bool
Eq,Int -> FunctionDefinition db args ret -> ShowS
[FunctionDefinition db args ret] -> ShowS
FunctionDefinition db args ret -> String
(Int -> FunctionDefinition db args ret -> ShowS)
-> (FunctionDefinition db args ret -> String)
-> ([FunctionDefinition db args ret] -> ShowS)
-> Show (FunctionDefinition db args ret)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall k (db :: k) k (args :: k) k (ret :: k).
Int -> FunctionDefinition db args ret -> ShowS
forall k (db :: k) k (args :: k) k (ret :: k).
[FunctionDefinition db args ret] -> ShowS
forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret -> String
showList :: [FunctionDefinition db args ret] -> ShowS
$cshowList :: forall k (db :: k) k (args :: k) k (ret :: k).
[FunctionDefinition db args ret] -> ShowS
show :: FunctionDefinition db args ret -> String
$cshow :: forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret -> String
showsPrec :: Int -> FunctionDefinition db args ret -> ShowS
$cshowsPrec :: forall k (db :: k) k (args :: k) k (ret :: k).
Int -> FunctionDefinition db args ret -> ShowS
Show,(forall x.
 FunctionDefinition db args ret
 -> Rep (FunctionDefinition db args ret) x)
-> (forall x.
    Rep (FunctionDefinition db args ret) x
    -> FunctionDefinition db args ret)
-> Generic (FunctionDefinition db args ret)
forall x.
Rep (FunctionDefinition db args ret) x
-> FunctionDefinition db args ret
forall x.
FunctionDefinition db args ret
-> Rep (FunctionDefinition db args ret) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall k (db :: k) k (args :: k) k (ret :: k) x.
Rep (FunctionDefinition db args ret) x
-> FunctionDefinition db args ret
forall k (db :: k) k (args :: k) k (ret :: k) x.
FunctionDefinition db args ret
-> Rep (FunctionDefinition db args ret) x
$cto :: forall k (db :: k) k (args :: k) k (ret :: k) x.
Rep (FunctionDefinition db args ret) x
-> FunctionDefinition db args ret
$cfrom :: forall k (db :: k) k (args :: k) k (ret :: k) x.
FunctionDefinition db args ret
-> Rep (FunctionDefinition db args ret) x
GHC.Generic,FunctionDefinition db args ret -> ()
(FunctionDefinition db args ret -> ())
-> NFData (FunctionDefinition db args ret)
forall a. (a -> ()) -> NFData a
forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret -> ()
rnf :: FunctionDefinition db args ret -> ()
$crnf :: forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret -> ()
NFData)
instance RenderSQL (FunctionDefinition db args ret) where
  renderSQL :: FunctionDefinition db args ret -> ByteString
renderSQL = FunctionDefinition db args ret -> ByteString
forall k (db :: k) k (args :: k) k (ret :: k).
FunctionDefinition db args ret -> ByteString
renderFunctionDefinition