{-# LANGUAGE
AllowAmbiguousTypes
, ConstraintKinds
, DeriveAnyClass
, DeriveGeneric
, FlexibleContexts
, FlexibleInstances
, FunctionalDependencies
, GADTs
, LambdaCase
, OverloadedStrings
, QuantifiedConstraints
, RankNTypes
, ScopedTypeVariables
, StandaloneDeriving
, TypeApplications
, TypeFamilyDependencies
, TypeInType
, TypeOperators
, UndecidableInstances
, UndecidableSuperClasses
#-}
module Squeal.PostgreSQL.Type.Schema
(
PGType (..)
, NullType (..)
, RowType
, FromType
, ColumnType
, ColumnsType
, TableType
, SchemumType (..)
, IndexType (..)
, FunctionType
, ReturnsType (..)
, SchemaType
, SchemasType
, Public
, SubDB
, SubsetDB
, ElemDB
, (:=>)
, Optionality (..)
, TableConstraint (..)
, TableConstraints
, Uniquely
, IsPGlabel (..)
, PGlabel (..)
, Create
, CreateIfNotExists
, CreateOrReplace
, Drop
, DropSchemum
, DropIfExists
, DropSchemumIfExists
, Alter
, AlterIfExists
, Rename
, RenameIfExists
, SetSchema
, ConstraintInvolves
, DropIfConstraintsInvolve
, PGNum
, PGIntegral
, PGFloating
, PGJsonType
, PGJsonKey
, SamePGType
, AllNotNull
, NotAllNull
, NullifyType
, NullifyRow
, NullifyFrom
, TableToColumns
, ColumnsToRow
, TableToRow
, Updatable
, AllUnique
, IsNotElem
, DbEnums
, SchemaEnums
, DbRelations
, SchemaRelations
, FindQualified
, FindName
, FindNamespace
, PrettyPrintPartitionedSchema
, PartitionedSchema(..)
, PartitionSchema
, SchemaFunctions
, SchemaIndexes
, SchemaProcedures
, SchemaTables
, SchemaTypes
, SchemaUnsafes
, SchemaViews
, IntersperseNewlines
, FilterNonEmpty
, FieldIfNonEmpty
, PartitionSchema'
) where
import Control.Category
import Data.Kind
import Data.Monoid hiding (All)
import Data.Type.Bool
import Generics.SOP
import GHC.TypeLits
import Prelude hiding (id, (.))
import Squeal.PostgreSQL.Type.Alias
import Squeal.PostgreSQL.Type.List
import Squeal.PostgreSQL.Render
data PGType
= PGbool
| PGint2
| PGint4
| PGint8
| PGnumeric
| PGfloat4
| PGfloat8
| PGmoney
| PGchar Nat
| PGvarchar Nat
| PGtext
| PGbytea
| PGtimestamp
| PGtimestamptz
| PGdate
| PGtime
| PGtimetz
| PGinterval
| PGuuid
| PGinet
| PGjson
| PGjsonb
| PGvararray NullType
| PGfixarray [Nat] NullType
| PGenum [Symbol]
| PGcomposite RowType
| PGtsvector
| PGtsquery
| PGoid
| PGrange PGType
| UnsafePGType Symbol
data NullType
= Null PGType
| NotNull PGType
type (:=>) constraint ty = '(constraint,ty)
infixr 7 :=>
data Optionality
= Def
| NoDef
type ColumnType = (Optionality,NullType)
type ColumnsType = [(Symbol,ColumnType)]
type instance PrettyPrintHaystack (haystack :: ColumnsType) =
'PrettyPrintInfo ('Text "column definition (ColumnType)") ('Text "table (ColumnsType)") ('ShowType (Sort (MapFst haystack)))
data TableConstraint
= Check [Symbol]
| Unique [Symbol]
| PrimaryKey [Symbol]
| ForeignKey [Symbol] Symbol Symbol [Symbol]
type TableConstraints = [(Symbol,TableConstraint)]
type instance PrettyPrintHaystack (haystack :: TableConstraints) =
'PrettyPrintInfo ('Text "constraint (TableConstraint)") ('Text "table (TableConstraints)") ('ShowType (Sort (MapFst haystack)))
type family Uniquely
(key :: [Symbol])
(constraints :: TableConstraints) :: Constraint where
Uniquely key (uq ::: 'Unique key ': constraints) = ()
Uniquely key (pk ::: 'PrimaryKey key ': constraints) = ()
Uniquely key (_ ': constraints) = Uniquely key constraints
type TableType = (TableConstraints,ColumnsType)
type RowType = [(Symbol,NullType)]
type instance PrettyPrintHaystack (haystack :: RowType) =
'PrettyPrintInfo ('Text "column (NullType)") ('Text "row (RowType)") ('ShowType (Sort (MapFst haystack)))
type FromType = [(Symbol,RowType)]
type instance PrettyPrintHaystack (haystack :: FromType) =
'PrettyPrintInfo ('Text "row (RowType)") ('Text "from clause (FromType)") ('ShowType (Sort (MapFst haystack)))
type family ColumnsToRow (columns :: ColumnsType) :: RowType where
ColumnsToRow (column ::: _ :=> ty ': columns) =
column ::: ty ': ColumnsToRow columns
ColumnsToRow '[] = '[]
type family TableToColumns (table :: TableType) :: ColumnsType where
TableToColumns (constraints :=> columns) = columns
type family TableToRow (table :: TableType) :: RowType where
TableToRow tab = ColumnsToRow (TableToColumns tab)
type PGNum =
'[ 'PGint2, 'PGint4, 'PGint8, 'PGnumeric, 'PGfloat4, 'PGfloat8]
type PGFloating = '[ 'PGfloat4, 'PGfloat8, 'PGnumeric]
type PGIntegral = '[ 'PGint2, 'PGint4, 'PGint8]
class SamePGType
(ty0 :: (Symbol,ColumnType)) (ty1 :: (Symbol,ColumnType)) where
instance ty0 ~ ty1 => SamePGType
(alias0 ::: def0 :=> null0 ty0)
(alias1 ::: def1 :=> null1 ty1)
type family AllNotNull (columns :: ColumnsType) :: Constraint where
AllNotNull (_ ::: _ :=> 'NotNull _ ': columns) = AllNotNull columns
AllNotNull '[] = ()
type family NotAllNull (columns :: ColumnsType) :: Constraint where
NotAllNull (_ ::: _ :=> 'NotNull _ ': _) = ()
NotAllNull (_ ::: _ :=> 'Null _ ': columns) = NotAllNull columns
type family NullifyType (ty :: NullType) :: NullType where
NullifyType (null ty) = 'Null ty
type family NullifyRow (columns :: RowType) :: RowType where
NullifyRow (column ::: ty ': columns) =
column ::: NullifyType ty ': NullifyRow columns
NullifyRow '[] = '[]
type family NullifyFrom (tables :: FromType) :: FromType where
NullifyFrom (table ::: columns ': tables) =
table ::: NullifyRow columns ': NullifyFrom tables
NullifyFrom '[] = '[]
type family Create alias x xs where
Create alias x '[] = '[alias ::: x]
Create alias x (alias ::: y ': xs) = TypeError
('Text "Create: alias "
':<>: 'ShowType alias
':<>: 'Text "already exists")
Create alias y (x ': xs) = x ': Create alias y xs
type family CreateIfNotExists alias x xs where
CreateIfNotExists alias x '[] = '[alias ::: x]
CreateIfNotExists alias x (alias ::: y ': xs) = alias ::: y ': xs
CreateIfNotExists alias y (x ': xs) = x ': CreateIfNotExists alias y xs
type family CreateOrReplace alias x xs where
CreateOrReplace alias x '[] = '[alias ::: x]
CreateOrReplace alias x (alias ::: x ': xs) = alias ::: x ': xs
CreateOrReplace alias x (alias ::: y ': xs) = TypeError
('Text "CreateOrReplace: expected type "
':<>: 'ShowType x
':<>: 'Text " but alias "
':<>: 'ShowType alias
':<>: 'Text " has type "
':<>: 'ShowType y)
CreateOrReplace alias y (x ': xs) = x ': CreateOrReplace alias y xs
type family Drop alias xs where
Drop alias '[] = TypeError
('Text "Drop: alias "
':<>: 'ShowType alias
':<>: 'Text " does not exist" )
Drop alias (alias ::: x ': xs) = xs
Drop alias (x ': xs) = x ': Drop alias xs
type family DropSchemum alias sch xs where
DropSchemum alias sch '[] = TypeError
('Text "DropSchemum: alias "
':<>: 'ShowType alias
':<>: 'Text " does not exist" )
DropSchemum alias sch (alias ::: sch x ': xs) = xs
DropSchemum alias sch0 (alias ::: sch1 x ': xs) = TypeError
('Text "DropSchemum: expected schemum "
':<>: 'ShowType sch0
':<>: 'Text " but alias "
':<>: 'ShowType alias
':<>: 'Text " has schemum "
':<>: 'ShowType sch1)
DropSchemum alias sch (x ': xs) = x ': DropSchemum alias sch xs
type family DropIfExists alias xs where
DropIfExists alias '[] = '[]
DropIfExists alias (alias ::: x ': xs) = xs
DropIfExists alias (x ': xs) = x ': DropIfExists alias xs
type family DropSchemumIfExists alias sch xs where
DropSchemumIfExists alias sch '[] = '[]
DropSchemumIfExists alias sch (alias ::: sch x ': xs) = xs
DropSchemumIfExists alias sch0 (alias ::: sch1 x ': xs) = TypeError
('Text "DropSchemumIfExists: expected schemum "
':<>: 'ShowType sch1
':<>: 'Text " but alias "
':<>: 'ShowType alias
':<>: 'Text " has schemum "
':<>: 'ShowType sch0)
DropSchemumIfExists alias sch (x ': xs) = x ': DropSchemumIfExists alias sch xs
type family Alter alias x xs where
Alter alias x '[] = TypeError
('Text "Alter: alias "
':<>: 'ShowType alias
':<>: 'Text " does not exist" )
Alter alias x1 (alias ::: x0 ': xs) = alias ::: x1 ': xs
Alter alias x1 (x0 ': xs) = x0 ': Alter alias x1 xs
type family AlterIfExists alias x xs where
AlterIfExists alias x '[] = '[]
AlterIfExists alias x1 (alias ::: x0 ': xs) = alias ::: x1 ': xs
AlterIfExists alias x1 (x0 ': xs) = x0 ': AlterIfExists alias x1 xs
type family Rename alias0 alias1 xs where
Rename alias0 alias1 '[] = TypeError
('Text "Rename: alias "
':<>: 'ShowType alias0
':<>: 'Text " does not exist" )
Rename alias0 alias1 ((alias0 ::: x0) ': xs) = (alias1 ::: x0) ': xs
Rename alias0 alias1 (x ': xs) = x ': Rename alias0 alias1 xs
type family RenameIfExists alias0 alias1 xs where
RenameIfExists alias x '[] = '[]
RenameIfExists alias0 alias1 ((alias0 ::: x0) ': xs) = (alias1 ::: x0) ': xs
RenameIfExists alias0 alias1 (x ': xs) = x ': RenameIfExists alias0 alias1 xs
type family SetSchema sch0 sch1 schema0 schema1 obj srt ty db where
SetSchema sch0 sch1 schema0 schema1 obj srt ty db = Alter sch1
(Create obj (srt ty) schema1)
(Alter sch0 (DropSchemum obj srt schema0) db)
type family SubDB (db0 :: SchemasType) (db1 :: SchemasType) :: Bool where
SubDB '[] db1 = 'True
SubDB (sch ': db0) '[] = 'False
SubDB (sch ::: schema0 ': db0) (sch ::: schema1 ': db1) =
If (SubList schema0 schema1)
(SubDB db0 db1)
(SubDB (sch ::: schema0 ': db0) db1)
SubDB db0 (sch1 ': db1) = SubDB db0 db1
type family SubsetDB (db0 :: SchemasType) (db1 :: SchemasType) :: Bool where
SubsetDB '[] db1 = 'True
SubsetDB (sch ': db0) db1 = ElemDB sch db1 && SubsetDB db0 db1
type family ElemDB (sch :: (Symbol, SchemaType)) (db :: SchemasType) :: Bool where
ElemDB sch '[] = 'False
ElemDB (sch ::: schema0) (sch ::: schema1 ': _) = SubsetList schema0 schema1
ElemDB sch (_ ': schs) = ElemDB sch schs
type family ConstraintInvolves column constraint where
ConstraintInvolves column ('Check columns) = column `Elem` columns
ConstraintInvolves column ('Unique columns) = column `Elem` columns
ConstraintInvolves column ('PrimaryKey columns) = column `Elem` columns
ConstraintInvolves column ('ForeignKey columns sch tab refcolumns)
= column `Elem` columns
type family DropIfConstraintsInvolve column constraints where
DropIfConstraintsInvolve column '[] = '[]
DropIfConstraintsInvolve column (alias ::: constraint ': constraints)
= If (ConstraintInvolves column constraint)
(DropIfConstraintsInvolve column constraints)
(alias ::: constraint ': DropIfConstraintsInvolve column constraints)
data SchemumType
= Table TableType
| View RowType
| Typedef PGType
| Index IndexType
| Function FunctionType
| Procedure [NullType]
| UnsafeSchemum Symbol
type FunctionType = ([NullType], ReturnsType)
data IndexType
= Btree
| Hash
| Gist
| Spgist
| Gin
| Brin
data ReturnsType
= Returns NullType
| ReturnsTable RowType
type SchemaType = [(Symbol,SchemumType)]
data PartitionedSchema = PartitionedSchema
{ PartitionedSchema -> [(Symbol, TableType)]
_tables :: [(Symbol, TableType)]
, PartitionedSchema -> [(Symbol, RowType)]
_views :: [(Symbol, RowType)]
, PartitionedSchema -> [(Symbol, PGType)]
_types :: [(Symbol, PGType)]
, PartitionedSchema -> [(Symbol, IndexType)]
_indexes :: [(Symbol, IndexType)]
, PartitionedSchema -> [(Symbol, FunctionType)]
_functions :: [(Symbol, FunctionType)]
, PartitionedSchema -> [(Symbol, [NullType])]
_procedures :: [(Symbol, [NullType])]
, PartitionedSchema -> [(Symbol, Symbol)]
_unsafes :: [(Symbol, Symbol)]
}
type PartitionSchema schema = PartitionSchema' schema ('PartitionedSchema '[] '[] '[] '[] '[] '[] '[])
type family PartitionSchema' (remaining :: SchemaType) (acc :: PartitionedSchema) :: PartitionedSchema where
PartitionSchema' '[] ps = ps
PartitionSchema' ('(s, 'Table table) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema ('(s, table) ': tables) views types indexes functions procedures unsafe)
PartitionSchema' ('(s, 'View view) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema tables ('(s, view) ': views) types indexes functions procedures unsafe)
PartitionSchema' ('(s, 'Typedef typ) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema tables views ('(s, typ) ': types) indexes functions procedures unsafe)
PartitionSchema' ('(s, 'Index ix) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema tables views types ('(s, ix) ': indexes) functions procedures unsafe)
PartitionSchema' ('(s, 'Function f) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema tables views types indexes ('(s, f) ': functions) procedures unsafe)
PartitionSchema' ('(s, 'Procedure p) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema tables views types indexes functions ('(s, p) ': procedures) unsafe)
PartitionSchema' ('(s, 'UnsafeSchemum u) ': rest) ('PartitionedSchema tables views types indexes functions procedures unsafe)
= PartitionSchema' rest ('PartitionedSchema tables views types indexes functions procedures ('(s, u) ': unsafe))
type family SchemaTables (schema :: PartitionedSchema) :: [(Symbol, TableType)] where
SchemaTables ('PartitionedSchema tables _ _ _ _ _ _) = tables
type family SchemaViews (schema :: PartitionedSchema) :: [(Symbol, RowType)] where
SchemaViews ('PartitionedSchema _ views _ _ _ _ _) = views
type family SchemaTypes (schema :: PartitionedSchema) :: [(Symbol, PGType)] where
SchemaTypes ('PartitionedSchema _ _ types _ _ _ _) = types
type family SchemaIndexes (schema :: PartitionedSchema) :: [(Symbol, IndexType)] where
SchemaIndexes ('PartitionedSchema _ _ _ indexes _ _ _) = indexes
type family SchemaFunctions (schema :: PartitionedSchema) :: [(Symbol, FunctionType)] where
SchemaFunctions ('PartitionedSchema _ _ _ _ functions _ _) = functions
type family SchemaProcedures (schema :: PartitionedSchema) :: [(Symbol, [NullType])] where
SchemaProcedures ('PartitionedSchema _ _ _ _ _ procedures _) = procedures
type family SchemaUnsafes (schema :: PartitionedSchema) :: [(Symbol, Symbol)] where
SchemaUnsafes ('PartitionedSchema _ _ _ _ _ _ unsafes) = unsafes
type family PrettyPrintPartitionedSchema (schema :: PartitionedSchema) :: ErrorMessage where
PrettyPrintPartitionedSchema schema = IntersperseNewlines (FilterNonEmpty
[ FieldIfNonEmpty "Tables" (SchemaTables schema)
, FieldIfNonEmpty "Views" (SchemaViews schema)
, FieldIfNonEmpty "Types" (SchemaTypes schema)
, FieldIfNonEmpty "Indexes" (SchemaIndexes schema)
, FieldIfNonEmpty "Functions" (SchemaFunctions schema)
, FieldIfNonEmpty "Procedures" (SchemaProcedures schema)
, FieldIfNonEmpty "Unsafe schema items" (SchemaUnsafes schema)
])
type family FieldIfNonEmpty (fieldName :: Symbol) (value :: [(Symbol, k)]) :: ErrorMessage where
FieldIfNonEmpty _ '[] = 'Text ""
FieldIfNonEmpty n xs = 'Text " " ':<>: 'Text n ':<>: 'Text ":" ':$$: 'Text " " ':<>: 'ShowType (Sort (MapFst xs))
type family FilterNonEmpty (ls :: [ErrorMessage]) :: [ErrorMessage] where
FilterNonEmpty ('Text "" ': rest) = FilterNonEmpty rest
FilterNonEmpty (x ': rest) = x ': FilterNonEmpty rest
FilterNonEmpty '[] = '[]
type family IntersperseNewlines (ls :: [ErrorMessage]) :: ErrorMessage where
IntersperseNewlines (x ': y ': '[]) = x ':$$: y
IntersperseNewlines (x ': xs) = x ':$$: IntersperseNewlines xs
IntersperseNewlines '[] = 'Text ""
type instance PrettyPrintHaystack (haystack :: SchemaType) =
'PrettyPrintInfo ('Text "table, view, typedef, index, function, or procedure (SchemumType)") ('Text "schema (SchemaType)")
( PrettyPrintPartitionedSchema (PartitionSchema haystack)
)
type SchemasType = [(Symbol,SchemaType)]
type instance PrettyPrintHaystack (haystack :: SchemasType) =
'PrettyPrintInfo ('Text "schema (SchemaType)") ('Text "database (SchemasType)") ('Text " " ':<>: 'ShowType (Sort (MapFst haystack)))
type family Public (schema :: SchemaType) :: SchemasType
where Public schema = '["public" ::: schema]
class IsPGlabel (label :: Symbol) expr where label :: expr
instance label ~ label1
=> IsPGlabel label (PGlabel label1) where label :: PGlabel label1
label = PGlabel label1
forall (label :: Symbol). PGlabel label
PGlabel
instance labels ~ '[label]
=> IsPGlabel label (NP PGlabel labels) where label :: NP PGlabel labels
label = PGlabel label
forall (label :: Symbol). PGlabel label
PGlabel PGlabel label -> NP PGlabel '[] -> NP PGlabel '[label]
forall k (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* NP PGlabel '[]
forall k (a :: k -> *). NP a '[]
Nil
instance IsPGlabel label (y -> K y label) where label :: y -> K y label
label = y -> K y label
forall k a (b :: k). a -> K a b
K
instance IsPGlabel label (y -> NP (K y) '[label]) where label :: y -> NP (K y) '[label]
label y
y = y -> K y label
forall k a (b :: k). a -> K a b
K y
y K y label -> NP (K y) '[] -> NP (K y) '[label]
forall k (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* NP (K y) '[]
forall k (a :: k -> *). NP a '[]
Nil
instance {-# OVERLAPPING #-}
IsPGlabel label0 (NS PGlabel (label0 ': labels)) where
label :: NS PGlabel (label0 : labels)
label = PGlabel label0 -> NS PGlabel (label0 : labels)
forall k (a :: k -> *) (x :: k) (xs :: [k]). a x -> NS a (x : xs)
Z PGlabel label0
forall (label :: Symbol). PGlabel label
PGlabel
instance {-# OVERLAPPABLE #-} IsPGlabel label0 (NS PGlabel labels)
=> IsPGlabel label0 (NS PGlabel (label1 ': labels)) where
label :: NS PGlabel (label1 : labels)
label = NS PGlabel labels -> NS PGlabel (label1 : labels)
forall k (a :: k -> *) (xs :: [k]) (x :: k).
NS a xs -> NS a (x : xs)
S (forall expr. IsPGlabel label0 expr => expr
forall (label :: Symbol) expr. IsPGlabel label expr => expr
label @label0)
data PGlabel (label :: Symbol) = PGlabel
instance KnownSymbol label => RenderSQL (PGlabel label) where
renderSQL :: PGlabel label -> ByteString
renderSQL PGlabel label
_ = ByteString
"\'" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> KnownSymbol label => ByteString
forall (s :: Symbol). KnownSymbol s => ByteString
renderSymbol @label ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"\'"
instance All KnownSymbol labels => RenderSQL (NP PGlabel labels) where
renderSQL :: NP PGlabel labels -> ByteString
renderSQL
= [ByteString] -> ByteString
commaSeparated
([ByteString] -> ByteString)
-> (NP PGlabel labels -> [ByteString])
-> NP PGlabel labels
-> ByteString
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. NP (K ByteString) labels -> [ByteString]
forall k l (h :: (k -> *) -> l -> *) (xs :: l) a.
(HCollapse h, SListIN h xs) =>
h (K a) xs -> CollapseTo h a
hcollapse
(NP (K ByteString) labels -> [ByteString])
-> (NP PGlabel labels -> NP (K ByteString) labels)
-> NP PGlabel labels
-> [ByteString]
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Proxy KnownSymbol
-> (forall (a :: Symbol).
KnownSymbol a =>
PGlabel a -> K ByteString a)
-> NP PGlabel labels
-> NP (K ByteString) labels
forall k l (h :: (k -> *) -> l -> *) (c :: k -> Constraint)
(xs :: l) (proxy :: (k -> Constraint) -> *) (f :: k -> *)
(f' :: k -> *).
(AllN (Prod h) c xs, HAp h) =>
proxy c
-> (forall (a :: k). c a => f a -> f' a) -> h f xs -> h f' xs
hcmap (Proxy KnownSymbol
forall k (t :: k). Proxy t
Proxy @KnownSymbol) (ByteString -> K ByteString a
forall k a (b :: k). a -> K a b
K (ByteString -> K ByteString a)
-> (PGlabel a -> ByteString) -> PGlabel a -> K ByteString a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. PGlabel a -> ByteString
forall sql. RenderSQL sql => sql -> ByteString
renderSQL)
type PGJsonKey = '[ 'PGint2, 'PGint4, 'PGtext ]
type PGJsonType = '[ 'PGjson, 'PGjsonb ]
class IsNotElem x isElem where
instance IsNotElem x 'False where
instance (TypeError ( 'Text "Cannot assign to "
':<>: 'ShowType alias
':<>: 'Text " more than once"))
=> IsNotElem '(alias, a) 'True where
class AllUnique (xs :: [(Symbol, a)]) where
instance AllUnique '[] where
instance (IsNotElem x (Elem x xs), AllUnique xs) => AllUnique (x ': xs) where
type Updatable table columns =
( All (HasIn (TableToColumns table)) columns
, AllUnique columns
, SListI (TableToColumns table) )
type family SchemaEnums schema where
SchemaEnums '[] = '[]
SchemaEnums (enum ::: 'Typedef ('PGenum labels) ': schema) =
enum ::: labels ': SchemaEnums schema
SchemaEnums (_ ': schema) = SchemaEnums schema
type family DbEnums db where
DbEnums '[] = '[]
DbEnums (sch ::: schema ': schemas) =
sch ::: SchemaEnums schema ': DbEnums schemas
type family SchemaRelations schema where
SchemaRelations '[] = '[]
SchemaRelations (ty ::: 'Typedef ('PGcomposite row) ': schema) =
ty ::: row ': SchemaRelations schema
SchemaRelations (tab ::: 'Table table ': schema) =
tab ::: TableToRow table ': SchemaRelations schema
SchemaRelations (vw ::: 'View row ': schema) =
vw ::: row ': SchemaRelations schema
SchemaRelations (_ ': schema) = SchemaRelations schema
type family DbRelations db where
DbRelations '[] = '[]
DbRelations (sch ::: schema ': schemas) =
sch ::: SchemaRelations schema ': DbRelations schemas
type family FindName xs x where
FindName '[] xs = 'Nothing
FindName ( '(name, x) ': _) x = 'Just name
FindName (_ ': xs) x = FindName xs x
type family FindNamespace err nsp name xss x where
FindNamespace err _ 'Nothing xss x = FindQualified err xss x
FindNamespace _ nsp ('Just name) _ _ = '(nsp, name)
type family FindQualified err xss x where
FindQualified err '[] x = TypeError
('Text err ':$$: 'ShowType x)
FindQualified err ( '(nsp, xs) ': xss) x =
FindNamespace err nsp (FindName xs x) xss x