packages feed

squeal-postgresql 0.8.0.0 → 0.8.1.0

raw patch · 6 files changed

+339/−17 lines, 6 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Squeal.PostgreSQL.Expression.Parameter: instance (GHC.TypeNats.KnownNat n, Squeal.PostgreSQL.Expression.Parameter.HasParameter (n GHC.TypeNats.- 1) xs x, params GHC.Types.~ (y : xs)) => Squeal.PostgreSQL.Expression.Parameter.HasParameter n params x
- Squeal.PostgreSQL.Expression.Parameter: instance (params GHC.Types.~ (x : xs)) => Squeal.PostgreSQL.Expression.Parameter.HasParameter 1 params x
- Squeal.PostgreSQL.Type.Alias: instance forall k kind (alias :: GHC.Types.Symbol) (err :: k) (fields :: [(GHC.Types.Symbol, kind)]) (field :: kind) (field' :: (GHC.Types.Symbol, kind)). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.HasErr err alias fields field) => Squeal.PostgreSQL.Type.Alias.HasErr err alias (field' : fields) field
- Squeal.PostgreSQL.Type.Alias: instance forall kind k (alias :: GHC.Types.Symbol) (field0 :: kind) (field1 :: kind) (err :: k) (fields :: [(GHC.Types.Symbol, kind)]). (GHC.TypeLits.KnownSymbol alias, field0 GHC.Types.~ field1) => Squeal.PostgreSQL.Type.Alias.HasErr err alias ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) field1
- Squeal.PostgreSQL.Type.Alias: type Has (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) = HasErr fields alias fields field
+ Squeal.PostgreSQL.Expression.Aggregate: instance ((TypeError ...), a GHC.Types.~ Squeal.PostgreSQL.Expression.Aggregate.AggregateArg) => Squeal.PostgreSQL.Expression.Aggregate.Aggregate a (Squeal.PostgreSQL.Expression.Expression 'Squeal.PostgreSQL.Type.Alias.Ungrouped)
+ Squeal.PostgreSQL.Expression.Parameter: instance ((TypeError ...), x GHC.Types.~ GHC.Types.Any) => Squeal.PostgreSQL.Expression.Parameter.HasParameter 0 params x
+ Squeal.PostgreSQL.Expression.Parameter: instance (GHC.TypeNats.KnownNat ix, Squeal.PostgreSQL.Expression.Parameter.HasParameter' ix params ix params x) => Squeal.PostgreSQL.Expression.Parameter.HasParameter ix params x
+ Squeal.PostgreSQL.Expression.Parameter: instance (GHC.TypeNats.KnownNat ix, Squeal.PostgreSQL.Expression.Parameter.HasParameter' originalIx allParams (ix GHC.TypeNats.- 1) xs x, params GHC.Types.~ (y : xs), Squeal.PostgreSQL.Expression.Parameter.ParamOutOfBoundsError originalIx allParams params) => Squeal.PostgreSQL.Expression.Parameter.HasParameter' originalIx allParams ix params x
+ Squeal.PostgreSQL.Expression.Parameter: instance (params GHC.Types.~ (y : xs), y GHC.Types.~ x, Squeal.PostgreSQL.Expression.Parameter.ParamOutOfBoundsError originalIx allParams params, Squeal.PostgreSQL.Expression.Parameter.ParamTypeMismatchError originalIx allParams x y) => Squeal.PostgreSQL.Expression.Parameter.HasParameter' originalIx allParams 1 params x
+ Squeal.PostgreSQL.Type.Alias: PrettyPrintInfo :: ErrorMessage -> ErrorMessage -> ErrorMessage -> PrettyPrintInfo
+ Squeal.PostgreSQL.Type.Alias: [_haystackName] :: PrettyPrintInfo -> ErrorMessage
+ Squeal.PostgreSQL.Type.Alias: [_haystackPrettyPrint] :: PrettyPrintInfo -> ErrorMessage
+ Squeal.PostgreSQL.Type.Alias: [_needleName] :: PrettyPrintInfo -> ErrorMessage
+ Squeal.PostgreSQL.Type.Alias: class (KnownSymbol alias) => Has (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) | alias fields -> field
+ Squeal.PostgreSQL.Type.Alias: data PrettyPrintInfo
+ Squeal.PostgreSQL.Type.Alias: instance forall k (alias :: GHC.Types.Symbol) (field0 :: k) (field1 :: k) (allFields :: [(GHC.Types.Symbol, k)]) (fields :: [(GHC.Types.Symbol, k)]). (GHC.TypeLits.KnownSymbol alias, field0 GHC.Types.~ field1, Squeal.PostgreSQL.Type.Alias.MismatchError alias allFields field0 field1) => Squeal.PostgreSQL.Type.Alias.HasErr allFields alias ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) field1
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (allFields :: [(GHC.Types.Symbol, kind)]) (field :: kind). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.LookupFailedError alias allFields, field GHC.Types.~ GHC.Types.Any) => Squeal.PostgreSQL.Type.Alias.HasErr allFields alias '[] field
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (allFields :: [(GHC.Types.Symbol, kind)]) (fields :: [(GHC.Types.Symbol, kind)]) (field :: kind) (field' :: (GHC.Types.Symbol, kind)). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.HasErr allFields alias fields field) => Squeal.PostgreSQL.Type.Alias.HasErr allFields alias (field' : fields) field
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (field :: kind). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.HasErr '[] alias '[] field) => Squeal.PostgreSQL.Type.Alias.Has alias '[] field
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (field' :: (GHC.Types.Symbol, kind)) (fields :: [(GHC.Types.Symbol, kind)]) (field :: kind). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.HasErr (field' : fields) alias (field' : fields) field) => Squeal.PostgreSQL.Type.Alias.Has alias (field' : fields) field
+ Squeal.PostgreSQL.Type.Alias: instance forall kind (alias :: GHC.Types.Symbol) (field0 :: kind) (fields :: [(GHC.Types.Symbol, kind)]) (field1 :: kind). (GHC.TypeLits.KnownSymbol alias, Squeal.PostgreSQL.Type.Alias.HasErr ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) alias ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) field1) => Squeal.PostgreSQL.Type.Alias.Has alias ((alias Squeal.PostgreSQL.Type.Alias.::: field0) : fields) field1
+ Squeal.PostgreSQL.Type.Alias: type LookupFailedError needle haystack = LookupFailedError' (LookupFailedError' () (DefaultPrettyPrinter haystack) needle haystack) (PrettyPrintHaystack haystack) needle haystack
+ Squeal.PostgreSQL.Type.Alias: type MismatchError (alias :: Symbol) (fields :: [(Symbol, kind)]) (found :: kind) (expected :: kind) = MismatchError' (MismatchError' () (DefaultPrettyPrinter fields) alias fields found expected) (PrettyPrintHaystack fields) alias fields found expected
+ Squeal.PostgreSQL.Type.Alias: type family PrettyPrintHaystack (haystack :: [(Symbol, k)]) :: PrettyPrintInfo
+ Squeal.PostgreSQL.Type.List: type Sort ls = MergeSort (Twos ls)
+ Squeal.PostgreSQL.Type.Schema: PartitionedSchema :: [(Symbol, TableType)] -> [(Symbol, RowType)] -> [(Symbol, PGType)] -> [(Symbol, IndexType)] -> [(Symbol, FunctionType)] -> [(Symbol, [NullType])] -> [(Symbol, Symbol)] -> PartitionedSchema
+ Squeal.PostgreSQL.Type.Schema: [_functions] :: PartitionedSchema -> [(Symbol, FunctionType)]
+ Squeal.PostgreSQL.Type.Schema: [_indexes] :: PartitionedSchema -> [(Symbol, IndexType)]
+ Squeal.PostgreSQL.Type.Schema: [_procedures] :: PartitionedSchema -> [(Symbol, [NullType])]
+ Squeal.PostgreSQL.Type.Schema: [_tables] :: PartitionedSchema -> [(Symbol, TableType)]
+ Squeal.PostgreSQL.Type.Schema: [_types] :: PartitionedSchema -> [(Symbol, PGType)]
+ Squeal.PostgreSQL.Type.Schema: [_unsafes] :: PartitionedSchema -> [(Symbol, Symbol)]
+ Squeal.PostgreSQL.Type.Schema: [_views] :: PartitionedSchema -> [(Symbol, RowType)]
+ Squeal.PostgreSQL.Type.Schema: data PartitionedSchema
+ Squeal.PostgreSQL.Type.Schema: type PartitionSchema schema = PartitionSchema' schema ('PartitionedSchema '[] '[] '[] '[] '[] '[] '[])
- Squeal.PostgreSQL.Expression.Parameter: class KnownNat n => HasParameter (n :: Nat) (params :: [NullType]) (ty :: NullType) | n params -> ty
+ Squeal.PostgreSQL.Expression.Parameter: class KnownNat ix => HasParameter (ix :: Nat) (params :: [NullType]) (ty :: NullType) | ix params -> ty
- Squeal.PostgreSQL.Expression.Parameter: parameter :: HasParameter n params ty => TypeExpression db ty -> Expression grp lat with db params from ty
+ Squeal.PostgreSQL.Expression.Parameter: parameter :: HasParameter ix params ty => TypeExpression db ty -> Expression grp lat with db params from ty
- Squeal.PostgreSQL.Type.Alias: class KnownSymbol alias => HasErr err (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) | alias fields -> field
+ Squeal.PostgreSQL.Type.Alias: class KnownSymbol alias => HasErr (allFields :: [(Symbol, kind)]) (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) | alias fields -> field

Files

squeal-postgresql.cabal view
@@ -1,5 +1,5 @@ name: squeal-postgresql-version: 0.8.0.0+version: 0.8.1.0 synopsis: Squeal PostgreSQL Library description: Squeal is a type-safe embedding of PostgreSQL in Haskell homepage: https://github.com/morphismtech/squeal
src/Squeal/PostgreSQL/Expression/Aggregate.hs view
@@ -566,6 +566,48 @@   varPop = unsafeAggregate "var_pop"   varSamp = unsafeAggregate "var_samp" +-- provides a nicer type error when we forget to group by+-- note that we need to make our 'a' polymorphic so that we can still match when it's ambiguous+instance ( TypeError ('Text "Cannot use aggregate functions to construct an Ungrouped Expression. Add a 'groupBy' to your TableExpression. If you want to aggregate across the entire result set, use 'groupBy Nil'.")+         , a ~ AggregateArg+         ) => Aggregate a (Expression 'Ungrouped) where+  countStar = impossibleAggregateError+  count = impossibleAggregateError+  sum_ = impossibleAggregateError+  arrayAgg = impossibleAggregateError+  jsonAgg = impossibleAggregateError+  jsonbAgg = impossibleAggregateError+  bitAnd = impossibleAggregateError+  bitOr = impossibleAggregateError+  boolAnd = impossibleAggregateError+  boolOr = impossibleAggregateError+  every = impossibleAggregateError+  max_ = impossibleAggregateError+  min_ = impossibleAggregateError+  avg = impossibleAggregateError+  corr = impossibleAggregateError+  covarPop = impossibleAggregateError+  covarSamp = impossibleAggregateError+  regrAvgX = impossibleAggregateError+  regrAvgY = impossibleAggregateError+  regrCount = impossibleAggregateError+  regrIntercept = impossibleAggregateError+  regrR2 = impossibleAggregateError+  regrSlope = impossibleAggregateError+  regrSxx = impossibleAggregateError+  regrSxy = impossibleAggregateError+  regrSyy = impossibleAggregateError+  stddev = impossibleAggregateError+  stddevPop = impossibleAggregateError+  stddevSamp = impossibleAggregateError+  variance = impossibleAggregateError+  varPop = impossibleAggregateError+  varSamp = impossibleAggregateError++-- | helper function for our errors above+impossibleAggregateError :: a+impossibleAggregateError = error "impossible; called aggregate function for Ungrouped even though the Aggregate instance has a type error constraint."+ -- | escape hatch to define aggregate functions unsafeAggregate   :: SOP.SListI xs
src/Squeal/PostgreSQL/Expression/Parameter.hs view
@@ -21,6 +21,7 @@   , RankNTypes   , ScopedTypeVariables   , TypeApplications+  , TypeFamilies   , TypeOperators   , UndecidableInstances #-}@@ -31,6 +32,8 @@   , param   ) where +import Data.Kind (Constraint)+import GHC.Exts (Any) import GHC.TypeLits  import Squeal.PostgreSQL.Expression@@ -49,11 +52,11 @@ separately from the SQL command string, in which case `param`s are used to refer to the out-of-line data values. -}-class KnownNat n => HasParameter-  (n :: Nat)+class KnownNat ix => HasParameter+  (ix :: Nat)   (params :: [NullType])   (ty :: NullType)-  | n params -> ty where+  | ix params -> ty where     -- | `parameter` takes a `Nat` using type application and a `TypeExpression`.     --     -- >>> printSQL (parameter @1 int4)@@ -62,12 +65,58 @@       :: TypeExpression db ty       -> Expression grp lat with db params from ty     parameter ty = UnsafeExpression $ parenthesized $-      "$" <> renderNat @n <+> "::"+      "$" <> renderNat @ix <+> "::"         <+> renderSQL ty-instance {-# OVERLAPPING #-} params ~ (x ': xs) => HasParameter 1 params x-instance {-# OVERLAPPABLE #-}-  (KnownNat n, HasParameter (n-1) xs x, params ~ (y ': xs))-  => HasParameter n params x++-- we could do the check for 0 in @HasParameter'@, but this way forces checking 'ix' before delegating,+-- which has the nice effect of ambiguous 'ix' errors mentioning 'HasParameter' instead of @HasParameter'@+instance {-# OVERLAPS #-} (TypeError ('Text "Tried to get the param at index 0, but params are 1-indexed"), x ~ Any) => HasParameter 0 params x+instance {-# OVERLAPS #-} (KnownNat ix, HasParameter' ix params ix params x) => HasParameter ix params x++-- | @HasParameter'@ is an implementation detail of 'HasParameter' allowing us to+-- include the full parameter list in our errors. Generally speaking it shouldn't leak to users+-- of the library+class KnownNat ix => HasParameter'+  (originalIx :: Nat)+  (allParams :: [NullType])+  (ix :: Nat)+  (params :: [NullType])+  (ty :: NullType)+  | ix params -> ty where+instance {-# OVERLAPS #-}+  ( params ~ (y ': xs)+  , y ~ x -- having a separate 'y' type variable is required for 'ParamTypeMismatchError'+  , ParamOutOfBoundsError originalIx allParams params+  , ParamTypeMismatchError originalIx allParams x y+  ) => HasParameter' originalIx allParams 1 params x+instance {-# OVERLAPS #-}+  ( KnownNat ix+  , HasParameter' originalIx allParams (ix-1) xs x+  , params ~ (y ': xs)+  , ParamOutOfBoundsError originalIx allParams params+  )+  => HasParameter' originalIx allParams ix params x++-- | @ParamOutOfBoundsError@ reports a nicer error with more context when we try to do an out-of-bounds lookup successfully do a lookup but+-- find a different field than we expected, or when we find ourself out of bounds+type family ParamOutOfBoundsError (originalIx :: Nat) (allParams :: [NullType]) (params :: [NullType]) :: Constraint where+  ParamOutOfBoundsError originalIx allParams '[] = TypeError+    ('Text "Index " ':<>: 'ShowType originalIx ':<>: 'Text " is out of bounds in 1-indexed parameter list:" ':$$: 'ShowType allParams)+  ParamOutOfBoundsError _ _ _ = ()++-- | @ParamTypeMismatchError@ reports a nicer error with more context when we successfully do a lookup but+-- find a different field than we expected, or when we find ourself out of bounds+type family ParamTypeMismatchError  (originalIx :: Nat) (allParams :: [NullType]) (found :: NullType) (expected :: NullType) :: Constraint where+  ParamTypeMismatchError _ _ found found = ()+  ParamTypeMismatchError originalIx allParams found expected = TypeError+    (     'Text "Type mismatch when looking up param at index " ':<>: 'ShowType originalIx+    ':$$: 'Text "in 1-indexed parameter list:"+    ':$$: 'Text "  " ':<>: 'ShowType allParams+    ':$$: 'Text ""+    ':$$: 'Text "Expected: " ':<>: 'ShowType expected+    ':$$: 'Text "But found: " ':<>: 'ShowType found+    ':$$: 'Text ""+    )  -- | `param` takes a `Nat` using type application and for basic types, -- infers a `TypeExpression`.
src/Squeal/PostgreSQL/Type/Alias.hs view
@@ -47,6 +47,11 @@   , HasErr   , HasAll   , HasIn+    -- * Error reporting+  , LookupFailedError+  , PrettyPrintHaystack+  , PrettyPrintInfo(..)+  , MismatchError     -- * Qualified Aliases   , QualifiedAlias (..)   , IsQualified (..)@@ -58,6 +63,7 @@ import Control.DeepSeq import Data.ByteString (ByteString) import Data.String (fromString)+import GHC.Exts (Any, Constraint) import GHC.OverloadedLabels import GHC.TypeLits @@ -184,20 +190,90 @@ -- | @Has alias fields field@ is a constraint that proves that -- @fields@ has a field of @alias ::: field@, inferring @field@ -- from @alias@ and @fields@.-type Has (alias :: Symbol) (fields :: [(Symbol,kind)]) (field :: kind)-  = HasErr fields alias fields field+class (KnownSymbol alias) => Has (alias :: Symbol) (fields :: [(Symbol, kind)]) (field :: kind) | alias fields -> field+-- having these instances forces 'Has' to inspect 'alias' and 'fields' and thereby fail before delegating to+-- 'HasErr', which means 'Has' shows up in error messages instead of 'HasErr'+instance {-# OVERLAPPING #-} (KnownSymbol alias, HasErr (alias ::: field0 ': fields) alias (alias ::: field0 ': fields) field1)+  => Has alias (alias ::: field0 ': fields) field1+instance {-# OVERLAPPABLE #-} (KnownSymbol alias, HasErr (field' ': fields) alias (field' ': fields) field)+  => Has alias (field' ': fields) field+instance (KnownSymbol alias, HasErr '[] alias '[] field)+  => Has alias '[] field -{- | `HasErr` is like `Has` except it also retains the original+{- | 'HasErr' is like `Has` except it also retains the original list of fields being searched, so that error messages are more useful. -} class KnownSymbol alias =>-  HasErr err (alias :: Symbol) (fields :: [(Symbol,kind)]) (field :: kind)+  HasErr (allFields :: [(Symbol, kind)]) (alias :: Symbol) (fields :: [(Symbol,kind)]) (field :: kind)   | alias fields -> field where-instance {-# OVERLAPPING #-} (KnownSymbol alias, field0 ~ field1)-  => HasErr err alias (alias ::: field0 ': fields) field1-instance {-# OVERLAPPABLE #-} (KnownSymbol alias, HasErr err alias fields field)-  => HasErr err alias (field' ': fields) field+instance {-# OVERLAPPING #-} (KnownSymbol alias, field0 ~ field1, MismatchError alias allFields field0 field1)+  => HasErr allFields alias (alias ::: field0 ': fields) field1+instance {-# OVERLAPPABLE #-} (KnownSymbol alias, HasErr allFields alias fields field)+  => HasErr allFields alias (field' ': fields) field+instance ( KnownSymbol alias+         , LookupFailedError alias allFields -- report a nicer error+         , field ~ Any -- required to satisfy the fundep+         ) => HasErr allFields alias '[] field++-- | @MismatchError@ reports a nicer error with more context when we successfully do a lookup but+-- find a different field than we expected+type MismatchError (alias :: Symbol) (fields :: [(Symbol, kind)]) (found :: kind) (expected :: kind)+  = MismatchError' (MismatchError' () (DefaultPrettyPrinter fields) alias fields found expected) (PrettyPrintHaystack fields) alias fields found expected++-- | @MismatchError'@ is the workhorse behind @MismatchError@, but taking an additional type as the first argument. We can put another type error+-- in there which will only show if @MismatchError'@ is stuck; this allows us to fall back to @DefaultPrettyPrinter@ when a @PrettyPrintHaystack@ instance+-- is missing+type family MismatchError' (err :: Constraint) (ppInfo :: PrettyPrintInfo) (alias :: Symbol) (fields :: [(Symbol, kind)]) (found :: kind) (expected :: kind) :: Constraint where+  MismatchError' _ _ _ _ found found = ()+  MismatchError' _ ('PrettyPrintInfo needleName haystackName _) alias fields found expected = TypeError+    (     'Text "Type mismatch when looking up " ':<>: needleName ':<>: 'Text " named " ':<>: 'ShowType alias+    ':$$: 'Text "in " ':<>: haystackName ':<>: 'Text ":"+    -- we don't use a pretty haystack because we want to show the values+    ':$$: 'ShowType fields+    ':$$: 'Text ""+    ':$$: 'Text "Expected: " ':<>: 'ShowType expected+    ':$$: 'Text "But found: " ':<>: 'ShowType found+    ':$$: 'Text ""+    )++-- | @LookupFailedError@ reports a nicer error when we fail to look up some @needle@ in some @haystack@+type LookupFailedError needle haystack = LookupFailedError' (LookupFailedError' () (DefaultPrettyPrinter haystack) needle haystack) (PrettyPrintHaystack haystack) needle haystack++-- | @LookupFailedError'@ is the workhorse behind @LookupFailedError@, but taking an additional type as the first argument. We can put another type error+-- in there which will only show if @LookupFailedError'@ is stuck; this allows us to fall back to @DefaultPrettyPrinter@ when a @PrettyPrintHaystack@ instance+-- is missing+type family LookupFailedError' (fallbackForUnknownKind :: Constraint) (prettyPrintInfo :: PrettyPrintInfo) (needle :: Symbol) (haystack :: [(Symbol, k)]) :: Constraint where+  LookupFailedError' _ ('PrettyPrintInfo needleName haystackName prettyHaystack) needle rawHaystack = TypeError+    (     'Text "Could not find " ':<>: needleName ':<>: 'Text " named " ':<>: 'ShowType needle+    ':$$: 'Text "in " ':<>: haystackName ':<>: 'Text ":"+    ':$$: prettyHaystack+    ':$$: 'Text ""+    ':$$: 'Text "*Raw " ':<>: haystackName ':<>: 'Text "*:"+    ':$$: 'ShowType rawHaystack+    ':$$: 'Text ""+    )++-- | @PrettyPrintInfo@ is a data type intended to be used at the type level+-- which describes how to pretty print a haystack in our custom errors. The general intention is we use @PrettyPrintHaystack@+-- to define a more specific way of pretty printing our error information for each kind that we care about+data PrettyPrintInfo = PrettyPrintInfo+  { _needleName :: ErrorMessage+  , _haystackName :: ErrorMessage+  , _haystackPrettyPrint :: ErrorMessage+  }++-- | 'PrettyPrintHaystack' allows us to use the kind of our haystack to come up+-- with nicer errors. It is implemented as an open type family for dependency reasons+type family PrettyPrintHaystack (haystack :: [(Symbol, k)]) :: PrettyPrintInfo++-- | @DefaultPrettyPrinter@ provides a default we can use for kinds that don't provide an instance of @PrettyPrintInfo@,+-- although that should generally only be accidental+type family DefaultPrettyPrinter (haystack :: [(Symbol, k)]) :: PrettyPrintInfo where+  DefaultPrettyPrinter (haystack :: [(Symbol, k)]) = 'PrettyPrintInfo+    ('Text "some kind without a PrettyPrintHaystack instance ("  ':<>: 'ShowType k ':<>: 'Text ")")+    ('Text "associative list of that kind ([(Symbol, "  ':<>: 'ShowType k ':<>: 'Text ")])")+    ('ShowType (Sort (MapFst haystack)))  {-| @HasIn fields (alias ::: field)@ is a constraint that proves that @fields@ has a field of @alias ::: field@. It is used in @UPDATE@s to
src/Squeal/PostgreSQL/Type/List.hs view
@@ -41,6 +41,8 @@   , Elem   , In   , Length+  , MapFst+  , Sort   , SubList   , SubsetList   ) where@@ -154,3 +156,44 @@ type family SubsetList (xs :: [k]) (ys :: [k]) :: Bool where   SubsetList '[] ys = 'True   SubsetList (x ': xs) ys = Elem x ys && SubsetList xs ys++-- | 'Sort' sorts a type level list of 'Symbol's in ascending lexicographic order+type Sort ls = MergeSort (Twos ls)++-- | 'MergeSort' is the workhorse behind 'Sort'+type family MergeSort (ls :: [[Symbol]]) :: [Symbol] where+  MergeSort '[]  = '[]+  MergeSort '[x] = x+  MergeSort ls   = MergeSort (FoldMerge ls)++-- | @Two@s splits a type-level list into a list of sorted lists of length 2 (with a singelton list potentially at the end)+-- It is required for implementing 'MergeSort'+type family Twos (ls :: [k]) :: [[k]] where+  Twos (x ': y ': rs) = Merge '[x] '[y] ': Twos rs+  Twos '[x]           = '[ '[x]]+  Twos '[]            = '[]++-- | 'Merge' two sorted lists into one list+type family Merge (ls :: [Symbol]) (rs :: [Symbol]) :: [Symbol] where+  Merge '[] r = r+  Merge l '[] = l+  Merge (l ': ls) (r ': rs) = If (Leq l r) (l ': Merge ls (r ': rs)) (r ': Merge (l ': ls) rs)++-- | 'FoldMerge' folds over a list of sorted lists, merging them into a single sorted list+type family FoldMerge (ls :: [[Symbol]]) :: [[Symbol]] where+  FoldMerge (x ': y ': rs) = (Merge x y ': FoldMerge rs)+  FoldMerge '[x]           = '[x]+  FoldMerge '[]            = '[]++type Leq l r = OrderingIsLeq (CmpSymbol l r)++type family OrderingIsLeq (o :: Ordering) :: Bool where+  OrderingIsLeq 'LT = 'True+  OrderingIsLeq 'EQ = 'True+  OrderingIsLeq 'GT = 'False++-- | 'MapFst' takes the first value of each tuple of a type level list of tuples. Useful for getting+-- only the names in associatve lists+type family MapFst (ls :: [(j, k)]) :: [j] where+  MapFst ('(j, _) ': rest) = j ': MapFst rest+  MapFst '[] = '[]
src/Squeal/PostgreSQL/Type/Schema.hs view
@@ -49,7 +49,17 @@   , ReturnsType (..)   , SchemaType   , SchemasType+  , PrettyPrintPartitionedSchema   , Public+  , PartitionedSchema(..)+  , PartitionSchema+  , SchemaFunctions+  , SchemaIndexes+  , SchemaProcedures+  , SchemaTables+  , SchemaTypes+  , SchemaUnsafes+  , SchemaViews     -- * Database Subsets   , SubDB   , SubsetDB@@ -204,6 +214,9 @@ -- :} type ColumnsType = [(Symbol,ColumnType)] +type instance PrettyPrintHaystack (haystack :: ColumnsType) =+  'PrettyPrintInfo ('Text "column definition (ColumnType)") ('Text "table (ColumnsType)") ('ShowType (Sort (MapFst haystack)))+ -- | `TableConstraint` encodes various forms of data constraints -- of columns in a table. -- `TableConstraint`s give you as much control over the data in your tables@@ -225,6 +238,9 @@ -} type TableConstraints = [(Symbol,TableConstraint)] +type instance PrettyPrintHaystack (haystack :: TableConstraints) =+  'PrettyPrintInfo ('Text "constraint (TableConstraint)") ('Text "table (TableConstraints)") ('ShowType (Sort (MapFst haystack)))+ -- | A `ForeignKey` must reference columns that either are -- a `PrimaryKey` or form a `Unique` constraint. type family Uniquely@@ -261,12 +277,18 @@ -} type RowType = [(Symbol,NullType)] +type instance PrettyPrintHaystack (haystack :: RowType) =+  'PrettyPrintInfo ('Text "column (NullType)") ('Text "row (RowType)") ('ShowType (Sort (MapFst haystack)))+ {- | `FromType` is a row of `RowType`s. It can be thought of as a product, or horizontal gluing and is used in `Squeal.PostgreSQL.Query.From.FromClause`s and `Squeal.PostgreSQL.Query.Table.TableExpression`s. -} type FromType = [(Symbol,RowType)] +type instance PrettyPrintHaystack (haystack :: FromType) =+  'PrettyPrintInfo ('Text "row (RowType)") ('Text "from clause (FromType)") ('ShowType (Sort (MapFst haystack)))+ -- | `ColumnsToRow` removes column constraints. type family ColumnsToRow (columns :: ColumnsType) :: RowType where   ColumnsToRow (column ::: _ :=> ty ': columns) =@@ -571,6 +593,93 @@ -} type SchemaType = [(Symbol,SchemumType)] +-- | A @PartitionedSchema@ is a @SchemaType@ where each constructor of @SchemumType@ has+-- been separated into its own list+data PartitionedSchema = PartitionedSchema+  { _tables     :: [(Symbol, TableType)]+  , _views      :: [(Symbol, RowType)]+  , _types      :: [(Symbol, PGType)]+  , _indexes    :: [(Symbol, IndexType)]+  , _functions  :: [(Symbol, FunctionType)]+  , _procedures :: [(Symbol, [NullType])]+  , _unsafes    :: [(Symbol, Symbol)]+  }++-- | @PartitionSchema@ partitions a @SchemaType@ into a @PartitionedSchema@+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))++-- | Get the tables from a @PartitionedSchema@+type family SchemaTables (schema :: PartitionedSchema) :: [(Symbol, TableType)] where+  SchemaTables ('PartitionedSchema tables _ _ _ _ _ _) = tables+-- | Get the views from a @PartitionedSchema@+type family SchemaViews (schema :: PartitionedSchema) :: [(Symbol, RowType)] where+  SchemaViews ('PartitionedSchema _ views _ _ _ _ _) = views+-- | Get the typedefs from a @PartitionedSchema@+type family SchemaTypes (schema :: PartitionedSchema) :: [(Symbol, PGType)] where+  SchemaTypes ('PartitionedSchema _ _ types _ _ _ _) = types+-- | Get the indexes from a @PartitionedSchema@+type family SchemaIndexes (schema :: PartitionedSchema) :: [(Symbol, IndexType)] where+  SchemaIndexes ('PartitionedSchema _ _ _ indexes _ _ _) = indexes+-- | Get the functions from a @PartitionedSchema@+type family SchemaFunctions (schema :: PartitionedSchema) :: [(Symbol, FunctionType)] where+  SchemaFunctions ('PartitionedSchema _ _ _ _ functions _ _) = functions+-- | Get the procedured from a @PartitionedSchema@+type family SchemaProcedures (schema :: PartitionedSchema) :: [(Symbol, [NullType])] where+  SchemaProcedures ('PartitionedSchema _ _ _ _ _ procedures _) = procedures+-- | Get the unsafe schema types from a @PartitionedSchema@+type family SchemaUnsafes (schema :: PartitionedSchema) :: [(Symbol, Symbol)] where+  SchemaUnsafes ('PartitionedSchema _ _ _ _ _ _ unsafes) = unsafes++-- | @PrettyPrintPartitionedSchema@ makes a nice @ErrorMessage@ showing a @PartitionedSchema@,+-- only including the names of the things in it and not the values. Additionally, empty+-- fields are omitted+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)+  )+ {- | 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;@@ -587,6 +696,9 @@   so they do not collide with the names of other objects. -} type SchemasType = [(Symbol,SchemaType)]++type instance PrettyPrintHaystack (haystack :: SchemasType) =+  'PrettyPrintInfo ('Text "schema (SchemaType)") ('Text "database (SchemasType)") ('Text "  " ':<>: 'ShowType (Sort (MapFst haystack)))  -- | A type family to use for a single schema database. type family Public (schema :: SchemaType) :: SchemasType