-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Servant servers utilities. -- -- Basement for common Servant combinators like filtering, sorting, -- pagination and semantical logging. @package servant-util @version 0.2 module Servant.Util.Common.Common type family ApplicationLS x -- | Extract right side of type application. type family ApplicationRS x -- | Proves info about argument specifier of servant API. class ApiHasArgClass api where { -- | For arguments-specifiers of API, get argument type. E.g. Capture -- "cap" Int -> Int. type family ApiArg api :: Type; type ApiArg api = ApplicationRS api; } -- | Name of argument. E.g. name of argument specified by Capture -- "nyan" is nyan. apiArgName :: ApiHasArgClass api => Proxy api -> String -- | Name of argument. E.g. name of argument specified by Capture -- "nyan" is nyan. apiArgName :: forall n someApiType a. (ApiHasArgClass api, KnownSymbol n, api ~ someApiType n a) => Proxy api -> String type ApiHasArg subApi res = (ApiHasArgClass subApi, ApiHasArgInvariant subApi res Handler) -- | Modify handler in implementation of route. inRouteServer :: forall api api' ctx env. (Proxy api -> Context ctx -> Delayed env (Server api) -> Router env) -> (Server api' -> Server api) -> Proxy api' -> Context ctx -> Delayed env (Server api') -> Router env -- | Similar to symbolVal, but shorter in use. symbolValT :: forall s. KnownSymbol s => Text -- | Helper for passing type-level symbol at term-level. We do not use -- Proxy for this because defining instance IsLabel name -- (Proxy name) in a library is not a really good idea. data NameLabel (name :: Symbol) NameLabel :: NameLabel (name :: Symbol) instance (n1 GHC.Types.~ n2) => GHC.OverloadedLabels.IsLabel n1 (Servant.Util.Common.Common.NameLabel n2) instance (Servant.Server.Internal.ServerT (subApi Servant.API.Sub.:> res) m GHC.Types.~ (Servant.Util.Common.Common.ApiArg subApi -> Servant.Server.Internal.ServerT res m)) => Servant.Util.Common.Common.ApiHasArgInvariant subApi res m instance GHC.TypeLits.KnownSymbol s => Servant.Util.Common.Common.ApiHasArgClass (Servant.API.Capture.Capture s a) instance GHC.TypeLits.KnownSymbol s => Servant.Util.Common.Common.ApiHasArgClass (Servant.API.QueryParam.QueryParam' mods s a) instance GHC.TypeLits.KnownSymbol s => Servant.Util.Common.Common.ApiHasArgClass (Servant.API.QueryParam.QueryFlag s) instance Servant.Util.Common.Common.ApiHasArgClass (Servant.API.ReqBody.ReqBody ct a) module Servant.Util.Common.HList -- | Servant package defines their own HList, so we also can (to -- avoid a large dependency). data HList (f :: k -> Type) (l :: [k]) [HNil] :: HList f '[] [HCons] :: f a -> HList f as -> HList f (a : as) infixr 3 `HCons` (.*.) :: forall k (f :: k -> Type) (a :: k) (as :: [k]). f a -> HList f as -> HList f (a : as) infixr 3 .*. class HListFromTuple a where { type family HListTuple a :: Type; } htuple :: HListFromTuple a => HListTuple a -> a instance forall k (f :: k -> *). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[]) instance forall k (f :: k -> *) (a :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a]) instance forall k (f :: k -> *) (a :: k) (b :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b]) instance forall k (f :: k -> *) (a :: k) (b :: k) (c :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b, c]) instance forall k (f :: k -> *) (a :: k) (b :: k) (c :: k) (d :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b, c, d]) instance forall k (f :: k -> *) (a :: k) (b :: k) (c :: k) (d :: k) (e :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b, c, d, e]) instance forall k (f :: k -> *) (a :: k) (b :: k) (c :: k) (d :: k) (e :: k) (g :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b, c, d, e, g]) instance forall k (f :: k -> *) (a :: k) (b :: k) (c :: k) (d :: k) (e :: k) (g :: k) (h :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b, c, d, e, g, h]) instance forall k (f :: k -> *) (a :: k) (b :: k) (c :: k) (d :: k) (e :: k) (g :: k) (h :: k) (i :: k). Servant.Util.Common.HList.HListFromTuple (Servant.Util.Common.HList.HList f '[a, b, c, d, e, g, h, i]) -- | Everything which requires PolyKinded extension, extracted in -- order not to spoil the remaining code. module Servant.Util.Common.PolyKinds -- | Pair of type and its name as it appears in API. data TyNamedParam a TyNamedParam :: Symbol -> a -> TyNamedParam a -- | Convenient type alias for TyNamedParam. type (?:) = 'TyNamedParam type family TyNamedParamType p type family TyNamedParamsNames (params :: [TyNamedParam k]) :: [Symbol] -- | Extract info from SortingParams. class ReifyParamsNames (params :: [TyNamedParam k]) -- | Get all expected parameter names. reifyParamsNames' :: ReifyParamsNames params => [Text] reifyParamsNames :: forall params. ReifyParamsNames params => [Text] type family LookupParam (desc :: Symbol) (name :: Symbol) (params :: [TyNamedParam k]) :: k -- | All names are quaranteed to be unique, so taking set of them is safe -- (number of entires will be preserved). reifyParamsNamesSet :: forall params. ReifyParamsNames params => Set Text type family ParamsContainNoName (params :: [TyNamedParam k]) name :: Constraint type family Elem (a :: k) (l :: [k]) :: Bool -- | Type-level If. If True a b ==> a; If -- False a b ==> b type family If (cond :: Bool) (tru :: k) (fls :: k) :: k type family (==) (a :: k) (b :: k) :: Bool infix 4 == type family (&&) (a :: Bool) (b :: Bool) :: Bool infix 3 && type family (||) (a :: Bool) (b :: Bool) :: Bool infix 2 || type family (++) (as :: [k]) (bs :: [k]) :: [k] type family (//) (as :: [k]) (bs :: [k]) :: [k] type family InsSorted (s :: Symbol) (ss :: [Symbol]) :: [Symbol] type family UnionSorted (ss1 :: [Symbol]) (ss2 :: [Symbol]) :: [Symbol] -- | Bring a type-level data to term-level. -- -- We don't want to depend on large singletons library, so -- providing our own small parts. -- -- TODO: use this instead of custom typeclasses in other places. class Demote (ty :: k) demote :: Demote ty => Proxy ty -> Demoted k type family Demoted k :: Type -- | Pattern-match on type-level bool. tyBoolCase :: Demote b => Proxy (b :: Bool) -> Either (Dict (b ~ 'False)) (Dict (b ~ 'True)) instance Servant.Util.Common.PolyKinds.Demote 'GHC.Types.True instance Servant.Util.Common.PolyKinds.Demote 'GHC.Types.False instance Servant.Util.Common.PolyKinds.Demote 'GHC.Maybe.Nothing instance forall k (a :: k). Servant.Util.Common.PolyKinds.Demote a => Servant.Util.Common.PolyKinds.Demote ('GHC.Maybe.Just a) instance GHC.TypeNats.KnownNat a => Servant.Util.Common.PolyKinds.Demote a instance forall (name :: GHC.Types.Symbol) k (params :: [Servant.Util.Common.PolyKinds.TyNamedParam k]) (p :: k). (GHC.TypeLits.KnownSymbol name, Servant.Util.Common.PolyKinds.ReifyParamsNames params, Servant.Util.Common.PolyKinds.ParamsContainNoName params name) => Servant.Util.Common.PolyKinds.ReifyParamsNames ('Servant.Util.Common.PolyKinds.TyNamedParam name p : params) instance Servant.Util.Common.PolyKinds.ReifyParamsNames '[] module Servant.Util.Common module Servant.Util.Combinators.Sorting.Base -- | Servant API combinator which allows to accept sorting parameters as a -- query parameter. -- -- Example: with the following combinator -- --
-- SortingParams ["time" ?: Timestamp, "name" ?: Text] '[] ---- -- the endpoint can parse "sortBy=-time,+name" or -- "sortBy=desc(time),asc(name)" formats, which would mean sorting by -- mentioned fields lexicographically. All sorting subparameters are -- optional, as well as entire "sortBy" parameter. -- -- The second type-level list stands for the base sorting order, it will -- be applied in the end disregard the user's input. It is highly -- recommended to specify the base sorting that unambigously orders the -- result(for example - by the primary key of the database), otherwise -- pagination may behave unexpectedly for the client when it specifies no -- sorting. -- -- If you want the base sorting order to be overridable by the user, you -- can put the respective fields in both lists. For example, this -- combinator: -- --
-- SortingParams -- '["time" ?: Timestamp] -- ["id" ?: '(Id, 'Descendant), "time" ?: '(Timestamp, 'Ascendant)] ---- -- will sort results lexicographically by (Down id, time), but -- if the client specifies sorting by time, you will get sorting by -- (time, Down id) as the trailing "time" will not -- affect anything. -- -- It is preferred to put a base sorting at least by ID, this -- way results will be more deterministic. -- -- Your handler will be provided with SortingSpec argument which -- can later be passed in an appropriate function to perform sorting. data SortingParams (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) -- | How servant sees SortParams under the hood. type SortParamsExpanded allowed subApi = QueryParam "sortBy" (TaggedSortingItemsList allowed) :> subApi -- | What is passed to an endpoint, contains all sorting parameters -- provided by a user. data SortingSpec (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) SortingSpec :: [SortingItem] -> SortingSpec (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) -- | Sorting items provided by the user (lexicographical order). [ssProvided] :: SortingSpec (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) -> [SortingItem] -- | Base sorting items, that are present disregard the client's input -- (lexicographical order). -- -- This is a sort of virtual field, so such naming. ssBase :: forall base provided. SortingSpec provided base -> [SortingItem] -- | All sorting items with duplicates removed (lexicographical order). ssAll :: SortingSpec provided base -> [SortingItem] -- | Order of sorting. data SortingOrder Descendant :: SortingOrder Ascendant :: SortingOrder -- | Where to place null fields. data NullsSortingOrder NullsFirst :: NullsSortingOrder NullsLast :: NullsSortingOrder -- | Version SortingItem which remembers its name and parameter type -- at type level. In functions which belong to public API you will most -- probably want to use this datatype as a safer variant of -- SortingItem. newtype SortingItemTagged (provided :: TyNamedParam *) SortingItemTagged :: SortingItem -> SortingItemTagged (provided :: TyNamedParam *) [untagSortingItem] :: SortingItemTagged (provided :: TyNamedParam *) -> SortingItem -- | For a given field, user-supplied order of sorting. This type is -- primarly for internal use, see also SortingItemTagged. data SortingItem SortingItem :: Text -> SortingOrder -> SortingItem -- | Name of parameter. Always matches one in param, but we keep -- it at term-level as well for convenience. [siName] :: SortingItem -> Text -- | Sorting order on the given parameter. [siOrder] :: SortingItem -> SortingOrder -- | Tagged, because we want to retain list of allowed fields for parsing -- (in instance FromHttpApiData). type TaggedSortingItemsList provided = Tagged (provided :: [TyNamedParam *]) [SortingItem] -- | Order of sorting for type-level. -- -- Its constructors accept the type of thing we order by, e.g. Asc -- Id. data SortingOrderType k Desc :: k -> SortingOrderType k Asc :: k -> SortingOrderType k -- | Requires given type-level items to be valid specification of sorting. class ReifySortingItems (items :: [TyNamedParam (SortingOrderType *)]) reifySortingItems :: ReifySortingItems items => [SortingItem] -- | Maps base params to the form common for provided and -- base. type family BaseSortingToParam (base :: [TyNamedParam (SortingOrderType *)]) :: [TyNamedParam *] -- | All sorting params, provided + base. -- -- This does not yet remove duplicates from provided and -- base sets, we wait for specific use cases to decide how to -- handle this better. type family AllSortingParams (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) :: [TyNamedParam *] -- | For a given return type of an endpoint get corresponding sorting -- params that can be specified by user. This mapping is sensible, since -- we usually allow to sort only on fields appearing in endpoint's -- response. type family SortingParamProvidedOf a :: [TyNamedParam *] -- | For a given return type of an endpoint get corresponding base sorting -- params. type family SortingParamBaseOf a :: [TyNamedParam (SortingOrderType *)] -- | This you will most probably want to specify in API. type SortingParamsOf a = SortingParams (SortingParamProvidedOf a) (SortingParamBaseOf a) -- | This you will most probably want to specify in an endpoint -- implementation. type SortingSpecOf a = SortingSpec (SortingParamProvidedOf a) (SortingParamBaseOf a) instance GHC.Enum.Enum Servant.Util.Combinators.Sorting.Base.SortingOrder instance GHC.Classes.Eq Servant.Util.Combinators.Sorting.Base.SortingOrder instance GHC.Show.Show Servant.Util.Combinators.Sorting.Base.SortingOrder instance GHC.Enum.Enum Servant.Util.Combinators.Sorting.Base.NullsSortingOrder instance GHC.Classes.Eq Servant.Util.Combinators.Sorting.Base.NullsSortingOrder instance GHC.Show.Show Servant.Util.Combinators.Sorting.Base.NullsSortingOrder instance GHC.Show.Show Servant.Util.Combinators.Sorting.Base.SortingItem instance GHC.Show.Show (Servant.Util.Combinators.Sorting.Base.SortingItemTagged provided) instance Formatting.Buildable.Buildable (Servant.Util.Combinators.Sorting.Base.SortingItemTagged param) instance (Servant.Util.Combinators.Sorting.Base.ReifySortingOrder order, GHC.TypeLits.KnownSymbol name, Servant.Util.Combinators.Sorting.Base.ReifySortingItems items) => Servant.Util.Combinators.Sorting.Base.ReifySortingItems ('Servant.Util.Common.PolyKinds.TyNamedParam name (order field) : items) instance Servant.Util.Combinators.Sorting.Base.ReifySortingOrder 'Servant.Util.Combinators.Sorting.Base.Asc instance Servant.Util.Combinators.Sorting.Base.ReifySortingOrder 'Servant.Util.Combinators.Sorting.Base.Desc instance GHC.Show.Show (Servant.Util.Combinators.Sorting.Base.SortingSpec provided base) instance Servant.Util.Combinators.Sorting.Base.ReifySortingItems '[] instance Formatting.Buildable.Buildable Servant.Util.Combinators.Sorting.Base.SortingItem module Servant.Util.Combinators.Sorting.Swagger instance (Servant.Swagger.Internal.HasSwagger api, Servant.Util.Combinators.Sorting.Base.ReifySortingItems base, Servant.Util.Common.PolyKinds.ReifyParamsNames provided) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Sorting.Base.SortingParams provided base Servant.API.Sub.:> api) module Servant.Util.Combinators.Sorting.Server instance (Servant.Server.Internal.HasServer subApi ctx, Servant.Server.Internal.Context.HasContextEntry (ctx Servant.Server.Internal.Context..++ Servant.Server.Internal.ErrorFormatter.DefaultErrorFormatters) Servant.Server.Internal.ErrorFormatter.ErrorFormatters, Servant.Util.Combinators.Sorting.Base.ReifySortingItems base, Servant.Util.Common.PolyKinds.ReifyParamsNames provided) => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Sorting.Base.SortingParams provided base Servant.API.Sub.:> subApi) ctx instance Servant.Util.Common.PolyKinds.ReifyParamsNames allowed => Web.Internal.HttpApiData.FromHttpApiData (Servant.Util.Combinators.Sorting.Base.TaggedSortingItemsList allowed) -- | Manual construction of sorting spec. module Servant.Util.Combinators.Sorting.Construction -- | Helper for defining custom SortingSpecs, contains -- SortingItem corresponding to one of parameter in -- provided list. data SortingRequestItem (provided :: [TyNamedParam *]) -- | Ascendant sorting on a field with given name. asc :: forall name provided. (KnownSymbol name, KnownTypeName provided name provided) => NameLabel name -> SortingRequestItem provided -- | Ascendant sorting on a field with given name. desc :: forall name provided. (KnownSymbol name, KnownTypeName provided name provided) => NameLabel name -> SortingRequestItem provided -- | Make a sorting specification. Specified list should contain sorting on -- distinct fields; we do not enforce this at type-level for convenience. -- -- Example: -- --
-- -- -- -- sortingSpec :: SortingSpec ["id" ?: Int, "desc" ?: Text] -- sortingSpec = mkSortingSpec [asc #id] --mkSortingSpec :: ReifySortingItems base => [SortingRequestItem provided] -> SortingSpec provided base -- | Do not specify ordering. noSorting :: ReifySortingItems base => SortingSpec provided base instance GHC.Show.Show (Servant.Util.Combinators.Sorting.Construction.SortingRequestItem provided) instance Servant.Util.Combinators.Sorting.Base.ReifySortingItems base => GHC.Exts.IsList (Servant.Util.Combinators.Sorting.Base.SortingSpec provided base) instance Servant.Util.Combinators.Sorting.Base.ReifySortingItems base => Data.Default.Class.Default (Servant.Util.Combinators.Sorting.Base.SortingSpec provided base) module Servant.Util.Combinators.Sorting.Client instance Servant.Client.Core.HasClient.HasClient m subApi => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.Sorting.Base.SortingParams provided base Servant.API.Sub.:> subApi) instance Web.Internal.HttpApiData.ToHttpApiData (Servant.Util.Combinators.Sorting.Base.TaggedSortingItemsList provided) -- | Applying sorting specifications. module Servant.Util.Combinators.Sorting.Backend -- | Implementation of filtering backend. class SortingBackend backend where { -- | The part of object which we are filtering on, provided by server -- backend implementor. type family SortedValue backend a :: *; -- | What we require from sorted values in order to be sortable. type family SortedValueConstraint backend a :: Constraint; -- | A resulting ordering. type family BackendOrdering backend :: *; type SortedValueConstraint backend a = (); } -- | Implement SortingApp as sorting on the given field. backendFieldSort :: (SortingBackend backend, SortedValueConstraint backend a) => SortedValue backend a -> SortingApp backend ('TyNamedParam name a) fieldSort :: forall name a backend. (SortingBackend backend, SortedValueConstraint backend a) => SortedValue backend a -> SortingApp backend ('TyNamedParam name a) -- | A function defining a way to apply the given SortingItem (which -- is sorting order on a single parameter). newtype SortingApp backend param SortingApp :: (SortingItemTagged param -> BackendOrdering backend) -> SortingApp backend param -- | List of SortingApp functions. Describes how to apply -- SortingSpec params (each of possible SortingItem) to -- an SQL query. -- -- Instance of this type can be created using fieldSort function. -- For example: -- --
-- sortingSpecApp :: SortingSpecApp ["course" ?: Course, "desc" ?: Text] -- sortingSpecApp = -- fieldSort "course" courseField .*. -- fieldSort "desc" descField .*. -- HNil ---- -- Annotating fieldSort call with parameter name is not mandatory -- but recommended to prevent possible mistakes in fieldSorts -- ordering. type SortingSpecApp backend (allParams :: [TyNamedParam *]) = HList (SortingApp backend) allParams -- | Lookup for appropriate SortingApp in SortingSpecApp and -- apply it to SortingItem. class ApplyToSortItem backend params -- | Apply spec app to the given SortingItem We return Maybe -- here (instead of forcing presence at type-level) for convenience. applyToSortItem :: ApplyToSortItem backend params => SortingSpecApp backend params -> SortingItem -> Maybe (BackendOrdering backend) -- | Apply a given SortingSpecApp to a SortingSpec producing -- a pack of ordering values which define lexicographical sorting order. backendApplySorting :: forall provided base allParams backend. (allParams ~ AllSortingParams provided base, ApplyToSortItem backend allParams) => SortingSpec provided base -> SortingSpecApp backend allParams -> [BackendOrdering backend] instance Servant.Util.Combinators.Sorting.Backend.ApplyToSortItem backend '[] instance (GHC.TypeLits.KnownSymbol name, Servant.Util.Combinators.Sorting.Backend.ApplyToSortItem backend params) => Servant.Util.Combinators.Sorting.Backend.ApplyToSortItem backend ('Servant.Util.Common.PolyKinds.TyNamedParam name p : params) -- | Manual construction of sorting spec. module Servant.Util.Combinators.Sorting.Arbitrary instance Test.QuickCheck.Arbitrary.Arbitrary Servant.Util.Combinators.Sorting.Base.SortingOrder instance (Servant.Util.Combinators.Sorting.Base.ReifySortingItems base, Servant.Util.Common.PolyKinds.ReifyParamsNames provided) => Test.QuickCheck.Arbitrary.Arbitrary (Servant.Util.Combinators.Sorting.Base.SortingSpec provided base) -- | Allows to enable logging of requests and responses. module Servant.Util.Combinators.Logging -- | Enables logging for server which serves given api. -- -- config is a type at which you have to specify -- ServantLogConfig via reflection. This way was chosen because -- the least thing we need in config is LoggerName, and we want -- to have <> on LoggerNames thus -- KnownSymbol is not enough. -- -- This logging will report -- --
-- SortingParams ["time" ?: Timestamp, "name" ?: Text] '[] ---- -- the endpoint can parse "sortBy=-time,+name" or -- "sortBy=desc(time),asc(name)" formats, which would mean sorting by -- mentioned fields lexicographically. All sorting subparameters are -- optional, as well as entire "sortBy" parameter. -- -- The second type-level list stands for the base sorting order, it will -- be applied in the end disregard the user's input. It is highly -- recommended to specify the base sorting that unambigously orders the -- result(for example - by the primary key of the database), otherwise -- pagination may behave unexpectedly for the client when it specifies no -- sorting. -- -- If you want the base sorting order to be overridable by the user, you -- can put the respective fields in both lists. For example, this -- combinator: -- --
-- SortingParams -- '["time" ?: Timestamp] -- ["id" ?: '(Id, 'Descendant), "time" ?: '(Timestamp, 'Ascendant)] ---- -- will sort results lexicographically by (Down id, time), but -- if the client specifies sorting by time, you will get sorting by -- (time, Down id) as the trailing "time" will not -- affect anything. -- -- It is preferred to put a base sorting at least by ID, this -- way results will be more deterministic. -- -- Your handler will be provided with SortingSpec argument which -- can later be passed in an appropriate function to perform sorting. data SortingParams (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) -- | What is passed to an endpoint, contains all sorting parameters -- provided by a user. data SortingSpec (provided :: [TyNamedParam *]) (base :: [TyNamedParam (SortingOrderType *)]) -- | Order of sorting for type-level. -- -- Its constructors accept the type of thing we order by, e.g. Asc -- Id. data SortingOrderType k Desc :: k -> SortingOrderType k Asc :: k -> SortingOrderType k -- | For a given return type of an endpoint get corresponding sorting -- params that can be specified by user. This mapping is sensible, since -- we usually allow to sort only on fields appearing in endpoint's -- response. type family SortingParamProvidedOf a :: [TyNamedParam *] -- | For a given return type of an endpoint get corresponding base sorting -- params. type family SortingParamBaseOf a :: [TyNamedParam (SortingOrderType *)] -- | This you will most probably want to specify in API. type SortingParamsOf a = SortingParams (SortingParamProvidedOf a) (SortingParamBaseOf a) -- | This you will most probably want to specify in an endpoint -- implementation. type SortingSpecOf a = SortingSpec (SortingParamProvidedOf a) (SortingParamBaseOf a) -- | Helper for defining custom SortingSpecs, contains -- SortingItem corresponding to one of parameter in -- provided list. data SortingRequestItem (provided :: [TyNamedParam *]) -- | Ascendant sorting on a field with given name. asc :: forall name provided. (KnownSymbol name, KnownTypeName provided name provided) => NameLabel name -> SortingRequestItem provided -- | Ascendant sorting on a field with given name. desc :: forall name provided. (KnownSymbol name, KnownTypeName provided name provided) => NameLabel name -> SortingRequestItem provided -- | Make a sorting specification. Specified list should contain sorting on -- distinct fields; we do not enforce this at type-level for convenience. -- -- Example: -- --
-- -- -- -- sortingSpec :: SortingSpec ["id" ?: Int, "desc" ?: Text] -- sortingSpec = mkSortingSpec [asc #id] --mkSortingSpec :: ReifySortingItems base => [SortingRequestItem provided] -> SortingSpec provided base -- | Do not specify ordering. noSorting :: ReifySortingItems base => SortingSpec provided base -- | Requires given type-level items to be valid specification of sorting. class ReifySortingItems (items :: [TyNamedParam (SortingOrderType *)]) -- | Convenient type alias for TyNamedParam. type (?:) = 'TyNamedParam module Servant.Util.Combinators.Filtering.Base -- | We support two kinds of filters. data FilterKind a -- | Automatic filter where different operations are supported (eq, in, -- cmp). When applied to backend, only filtered value should be supplied. AutoFilter :: a -> FilterKind a -- | User-provided value is passed to backend implementation as-is, and -- filtering on this value should be written manually. ManualFilter :: a -> FilterKind a type TyNamedFilter = TyNamedParam (FilterKind Type) -- | Servant API combinator which enables filtering on given fields. -- -- If type T appears with a name name in -- params argument, then query parameters of -- name[op]=value format will be accepted, where op is -- a filtering operation (e.g. equal, not equal, greater) and -- value is an item of type T we filter against. -- Multiple filters will form a conjunction. -- -- List of allowed filtering operations depends on type T and is -- specified by SupportedFilters type family. -- -- Operation argument is optional, when not specified "equality" filter -- is applied. -- -- Endpoint implementation will receive FilteringSpec value which -- contains information about all filters passed by user. You can later -- put it to an appropriate function to apply filtering. data FilteringParams (params :: [TyNamedFilter]) -- | For a type of field, get a list of supported filtering operations on -- this field. type family SupportedFilters ty :: [Type -> Type] -- | This is what you get in endpoint implementation, it contains all -- filters supplied by a user. Invariant: each filter correspond to some -- type mentioned in params. newtype FilteringSpec (params :: [TyNamedFilter]) FilteringSpec :: [SomeFilter params] -> FilteringSpec (params :: [TyNamedFilter]) -- | If no filtering command specified, think like if the given one was -- passed. pattern DefFilteringCmd :: Text -- | Some filter for an item of type a. Filter type is guaranteed -- to be one of SupportedFilters a. data SomeTypeAutoFilter a SomeTypeAutoFilter :: filter a -> SomeTypeAutoFilter a -- | Some filter for an item of type a. data TypeFilter (fk :: Type -> FilterKind Type) a -- | One of automatic filters for type a. Filter type is -- guaranteed to be one of SupportedFilters a. [TypeAutoFilter] :: SomeTypeAutoFilter a -> TypeFilter 'AutoFilter a -- | Manually implemented filter. [TypeManualFilter] :: a -> TypeFilter 'ManualFilter a -- | Some filter. This filter is guaranteed to match a type which is -- mentioned in params. data SomeFilter (params :: [TyNamedFilter]) [SomeFilter] :: (Typeable fk, Typeable a) => {sfName :: Text, sfFilter :: TypeFilter fk a} -> SomeFilter params extendSomeFilter :: SomeFilter params -> SomeFilter (param : params) castTypeFilter :: forall fk1 a1 fk2 a2. (Typeable fk1, Typeable a1, Typeable fk2, Typeable a2) => TypeFilter fk1 a1 -> Maybe (TypeFilter fk2 a2) -- | How auto filters appear in logging. class BuildableAutoFilter (filter :: Type -> Type) buildAutoFilter :: (BuildableAutoFilter filter, Buildable a) => Text -> filter a -> Builder -- | Application of a filter type to Servant API. class (Typeable filter, BuildableAutoFilter filter) => IsAutoFilter (filter :: Type -> Type) -- | For each supported filtering operation specifies a short plain-english -- description. autoFilterEnglishOpsNames :: IsAutoFilter filter => OpsDescriptions -- | For each supported filtering operation specifies parser for a -- filtering value. autoFilterParsers :: (IsAutoFilter filter, FromHttpApiData a) => Proxy filter -> Map Text (FilteringValueParser (filter a)) -- | Encode a filter to query parameter value. autoFilterEncode :: (IsAutoFilter filter, ToHttpApiData a) => filter a -> (Text, Text) mapAutoFilterValue :: IsAutoFilter filter => (a -> b) -> filter a -> filter b mapAutoFilterValue :: (IsAutoFilter filter, Functor filter) => (a -> b) -> filter a -> filter b -- | Multi-version of IsFilter. class AreAutoFilters (filters :: [Type -> Type]) mapFilterTypes :: AreAutoFilters filters => (forall filter. IsAutoFilter filter => Proxy filter -> a) -> Proxy filters -> [a] -- | Parses text on the right side of "=" sign in query parameters. newtype FilteringValueParser a FilteringValueParser :: (Text -> Either Text a) -> FilteringValueParser a -- | For each filtering operation specifies a short plain-english -- description. This is not a Map to prevent developer-defined -- entries order. type OpsDescriptions = [(Text, Text)] -- | Delegate to FromHttpApiData. parseFilteringValueAsIs :: FromHttpApiData a => FilteringValueParser a unsupportedFilteringValue :: Text -> FilteringValueParser a -- | Gather parsers from multiple filters. autoFiltersParsers :: forall filters a. (AreAutoFilters filters, FromHttpApiData a) => Map Text $ FilteringValueParser (SomeTypeAutoFilter a) -- | For a given return type of an endpoint get corresponding filtering -- params. This mapping is sensible, since we usually allow to filter -- only on fields appearing in endpoint's response. type family FilteringParamTypesOf a :: [TyNamedFilter] -- | This you will most probably want to specify in API. type FilteringParamsOf a = FilteringParams (FilteringParamTypesOf a) -- | This you will most probably want to specify in an endpoint -- implementation. type FilteringSpecOf a = FilteringSpec (FilteringParamTypesOf a) instance GHC.Base.Functor Servant.Util.Combinators.Filtering.Base.FilteringValueParser instance GHC.Exts.IsList (Servant.Util.Combinators.Filtering.Base.FilteringSpec params) instance GHC.Base.Functor Servant.Util.Combinators.Filtering.Base.SomeTypeAutoFilter instance Formatting.Buildable.Buildable a => Formatting.Buildable.Buildable (Data.Text.Internal.Text, Servant.Util.Combinators.Filtering.Base.SomeTypeAutoFilter a) instance Servant.Util.Combinators.Filtering.Base.AreAutoFilters '[] instance (Servant.Util.Combinators.Filtering.Base.IsAutoFilter filter, Servant.Util.Combinators.Filtering.Base.AreAutoFilters filters) => Servant.Util.Combinators.Filtering.Base.AreAutoFilters (filter : filters) module Servant.Util.Combinators.Filtering.Server -- | Application of filter params. class AreFilteringParams (params :: [TyNamedFilter]) instance Servant.Util.Combinators.Filtering.Server.AreFilteringParams '[] instance (Web.Internal.HttpApiData.FromHttpApiData ty, Data.Typeable.Internal.Typeable ty, Servant.Util.Combinators.Filtering.Base.AreAutoFilters (Servant.Util.Combinators.Filtering.Base.SupportedFilters ty), GHC.TypeLits.KnownSymbol name, Servant.Util.Combinators.Filtering.Server.AreFilteringParams params) => Servant.Util.Combinators.Filtering.Server.AreFilteringParams ('Servant.Util.Common.PolyKinds.TyNamedParam name ('Servant.Util.Combinators.Filtering.Base.AutoFilter ty) : params) instance (Web.Internal.HttpApiData.FromHttpApiData ty, Formatting.Buildable.Buildable ty, Data.Typeable.Internal.Typeable ty, GHC.TypeLits.KnownSymbol name, Servant.Util.Combinators.Filtering.Server.AreFilteringParams params) => Servant.Util.Combinators.Filtering.Server.AreFilteringParams ('Servant.Util.Common.PolyKinds.TyNamedParam name ('Servant.Util.Combinators.Filtering.Base.ManualFilter ty) : params) instance (Servant.Server.Internal.HasServer subApi ctx, Servant.Util.Combinators.Filtering.Server.AreFilteringParams params) => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Filtering.Base.FilteringParams params Servant.API.Sub.:> subApi) ctx module Servant.Util.Combinators.Filtering.Logging -- | Print a filter as it should appear in logs. class BuildSomeFilter params buildSomeFilter' :: BuildSomeFilter params => SomeFilter params -> Maybe Builder instance Servant.Util.Combinators.Filtering.Logging.BuildSomeFilter '[] instance (GHC.TypeLits.KnownSymbol name, Data.Typeable.Internal.Typeable a, Formatting.Buildable.Buildable a, Servant.Util.Combinators.Filtering.Logging.BuildSomeFilter params) => Servant.Util.Combinators.Filtering.Logging.BuildSomeFilter ('Servant.Util.Common.PolyKinds.TyNamedParam name ('Servant.Util.Combinators.Filtering.Base.AutoFilter a) : params) instance (GHC.TypeLits.KnownSymbol name, Data.Typeable.Internal.Typeable a, Formatting.Buildable.Buildable a, Servant.Util.Combinators.Filtering.Logging.BuildSomeFilter params) => Servant.Util.Combinators.Filtering.Logging.BuildSomeFilter ('Servant.Util.Common.PolyKinds.TyNamedParam name ('Servant.Util.Combinators.Filtering.Base.ManualFilter a) : params) instance (Servant.Util.Combinators.Logging.HasLoggingServer config lcontext subApi ctx, Servant.Util.Combinators.Filtering.Server.AreFilteringParams params, Servant.Util.Common.PolyKinds.ReifyParamsNames params, Servant.Util.Combinators.Filtering.Logging.BuildSomeFilter params) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.Util.Combinators.Filtering.Base.FilteringParams params Servant.API.Sub.:> subApi) ctx -- | Filter getters. -- -- Allows to get a value passed by user to a manual filter. Extracing -- auto filters is not allowed as soon as they are too complex to make -- anything useful with them anyway. module Servant.Util.Combinators.Filtering.Getters -- | Extract a value from manual filter. manualFilterValue :: forall name params filter filterKind. (filterKind ~ LookupParam "filter" name (params :: [TyNamedFilter]), filter ~ UnManualFilter filterKind, Typeable filter, KnownSymbol name) => NameLabel name -> FilteringSpec params -> [filter] module Servant.Util.Combinators.Filtering.Filters.Like pattern Esc :: Char -- | Whether search is case-sensitive. newtype CaseSensitivity CaseSensitivity :: Bool -> CaseSensitivity mkLikePattern :: LText -> Either Text LikePattern -- | Simple regexp pattern, . and * signed will be -- considered. Escaping is performed via prefixing with backslash. newtype LikePattern LikePatternUnsafe :: LText -> LikePattern [unLikePattern] :: LikePattern -> LText -- | Support for SQL's LIKE syntax. data FilterLike a FilterLike :: CaseSensitivity -> LikePattern -> FilterLike a mkLikePatternUnsafe :: LText -> LikePattern -- | Construct a filter that matches when text contains given substring. filterContains :: CaseSensitivity -> Text -> FilterLike a instance GHC.Base.Functor Servant.Util.Combinators.Filtering.Filters.Like.FilterLike instance Servant.Util.Combinators.Filtering.Base.BuildableAutoFilter Servant.Util.Combinators.Filtering.Filters.Like.FilterLike instance Servant.Util.Combinators.Filtering.Base.IsAutoFilter Servant.Util.Combinators.Filtering.Filters.Like.FilterLike instance Data.String.IsString Servant.Util.Combinators.Filtering.Filters.Like.LikePattern instance Formatting.Buildable.Buildable Servant.Util.Combinators.Filtering.Filters.Like.LikePattern instance Formatting.Buildable.Buildable Servant.Util.Combinators.Filtering.Filters.Like.CaseSensitivity module Servant.Util.Combinators.Filtering.Filters.General -- | Support for (==), (/=) and IN list -- operations. data FilterMatching a FilterMatching :: a -> FilterMatching a FilterNotMatching :: a -> FilterMatching a FilterItemsIn :: [a] -> FilterMatching a -- | Support for (<), (>), (<=) and -- (>=) operations. data FilterComparing a FilterGT :: a -> FilterComparing a FilterLT :: a -> FilterComparing a FilterGTE :: a -> FilterComparing a FilterLTE :: a -> FilterComparing a instance GHC.Base.Functor Servant.Util.Combinators.Filtering.Filters.General.FilterMatching instance GHC.Base.Functor Servant.Util.Combinators.Filtering.Filters.General.FilterComparing instance Servant.Util.Combinators.Filtering.Base.BuildableAutoFilter Servant.Util.Combinators.Filtering.Filters.General.FilterComparing instance Servant.Util.Combinators.Filtering.Base.IsAutoFilter Servant.Util.Combinators.Filtering.Filters.General.FilterComparing instance Servant.Util.Combinators.Filtering.Base.BuildableAutoFilter Servant.Util.Combinators.Filtering.Filters.General.FilterMatching instance Servant.Util.Combinators.Filtering.Base.IsAutoFilter Servant.Util.Combinators.Filtering.Filters.General.FilterMatching -- | Various filter types. module Servant.Util.Combinators.Filtering.Filters -- | Auto filters support for basic types. module Servant.Util.Combinators.Filtering.Support type NumericFilterTypes = [FilterMatching, FilterComparing] type TextFilterTypes = [FilterMatching, FilterComparing, FilterLike] type DatetimeFilterTypes = '[FilterComparing] type AllFilterTypes = '[FilterMatching, FilterComparing, FilterLike] -- | Helpers for defining filters manually. module Servant.Util.Combinators.Filtering.Construction -- | Return all items. noFilters :: FilteringSpec params -- | Build a filtering specification. Used along with -- OverloadedLabels extension and ($) / ($=) -- operators. -- -- Example: -- --
-- filteringSpec :: FilteringSpec ["id" ?: 'AutoFilter Int, "desc" ?: 'ManualFilter Text] -- filteringSpec = mkFilteringSpec -- [ -- Constructing an auto filter -- , #id ?/ FilterGT 0 -- -- -- The following two lines are equivalent -- , #id ?/ FilterMatching 5 -- , #id ?/= 5 -- -- -- Constructing a manually implemented filter -- , #desc ?/~ "You are my sunshine, my only sunshine" -- ] ---- -- You can freely use fromList instead of this function. mkFilteringSpec :: [SomeFilter params] -> FilteringSpec params -- | "Filter by" operation. Wraps a filter corresponding to the given name -- into SomeFilter which can later be passed to -- mkSomeFilter. (?/) :: forall name params filter. MkSomeFilter name filter params params => NameLabel name -> filter -> SomeFilter params infixr 0 ?/ -- | "Filter by matching" operation. (?/=) :: forall name params filter. MkSomeFilter name (FilterMatching filter) params params => NameLabel name -> filter -> SomeFilter params infixr 0 ?/= -- | Make a comparing filter. (?/<) :: forall name params filter. MkSomeFilter name (FilterComparing filter) params params => NameLabel name -> filter -> SomeFilter params infixr 0 ?/< -- | Make a comparing filter. (?/>) :: forall name params filter. MkSomeFilter name (FilterComparing filter) params params => NameLabel name -> filter -> SomeFilter params infixr 0 ?/> -- | Make a comparing filter. (?/<=) :: forall name params filter. MkSomeFilter name (FilterComparing filter) params params => NameLabel name -> filter -> SomeFilter params infixr 0 ?/<= -- | Make a comparing filter. (?/>=) :: forall name params filter. MkSomeFilter name (FilterComparing filter) params params => NameLabel name -> filter -> SomeFilter params infixr 0 ?/>= -- | Construct a (manual) filter from a value with the same representation -- as expected one. Helpful when newtypes are heavely used in API -- parameters. (?/~) :: forall name filter' params filter. (MkSomeFilter name filter' params params, Coercible filter filter') => NameLabel name -> filter -> SomeFilter params -- | Make a simple POSIX regex filter. textLike :: forall name params text. (MkSomeFilter name (FilterLike text) params params, HasCallStack) => NameLabel name -> LText -> SomeFilter params infixr 0 `textLike` -- | Make a simple POSIX regex case-insensitive filter. textILike :: forall name params text. (MkSomeFilter name (FilterLike text) params params, HasCallStack) => NameLabel name -> LText -> SomeFilter params infixr 0 `textILike` -- | Make a filter that checks whether the given text is included. textContains :: forall name params text. MkSomeFilter name (FilterLike text) params params => NameLabel name -> Text -> SomeFilter params infixr 0 `textContains` -- | Make a filter that checks whether the given text is included, -- case-insensitive. textIContains :: forall name params text. MkSomeFilter name (FilterLike text) params params => NameLabel name -> Text -> SomeFilter params infixr 0 `textIContains` instance forall k (name :: k) (origParams :: [Servant.Util.Common.PolyKinds.TyNamedParam (Servant.Util.Combinators.Filtering.Base.FilterKind *)]) filter. (TypeError ...) => Servant.Util.Combinators.Filtering.Construction.MkSomeFilter name filter origParams '[] instance (Servant.Util.Combinators.Filtering.Construction.MkTypeFilter filter fk a, GHC.TypeLits.KnownSymbol name, Data.Typeable.Internal.Typeable fk, Data.Typeable.Internal.Typeable a) => Servant.Util.Combinators.Filtering.Construction.MkSomeFilter name filter origParams ('Servant.Util.Common.PolyKinds.TyNamedParam name (fk a) : params) instance forall k (name :: k) filter (origParams :: [Servant.Util.Combinators.Filtering.Base.TyNamedFilter]) (params :: [Servant.Util.Combinators.Filtering.Base.TyNamedFilter]) (param :: Servant.Util.Combinators.Filtering.Base.TyNamedFilter). Servant.Util.Combinators.Filtering.Construction.MkSomeFilter name filter origParams params => Servant.Util.Combinators.Filtering.Construction.MkSomeFilter name filter origParams (param : params) instance (filter GHC.Types.~ filterType a, Servant.Util.Combinators.Filtering.Base.IsAutoFilter filterType, Servant.Util.Combinators.Filtering.Construction.IsSupportedFilter filterType a) => Servant.Util.Combinators.Filtering.Construction.MkTypeFilter filter 'Servant.Util.Combinators.Filtering.Base.AutoFilter a instance (filter GHC.Types.~ a) => Servant.Util.Combinators.Filtering.Construction.MkTypeFilter filter 'Servant.Util.Combinators.Filtering.Base.ManualFilter a instance Data.Default.Class.Default (Servant.Util.Combinators.Filtering.Base.FilteringSpec params) module Servant.Util.Combinators.Filtering.Client instance Servant.Util.Combinators.Filtering.Client.SomeFilterToReq '[] instance (GHC.TypeLits.KnownSymbol name, Data.Typeable.Internal.Typeable fk, Data.Typeable.Internal.Typeable a, Web.Internal.HttpApiData.ToHttpApiData a, Servant.Util.Combinators.Filtering.Client.SomeFilterToReq params) => Servant.Util.Combinators.Filtering.Client.SomeFilterToReq ('Servant.Util.Common.PolyKinds.TyNamedParam name (fk a) : params) instance (Servant.Client.Core.HasClient.HasClient m subApi, Servant.Util.Combinators.Filtering.Client.SomeFilterToReq params) => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.Filtering.Base.FilteringParams params Servant.API.Sub.:> subApi) -- | Provides base for filtering backend implementations. module Servant.Util.Combinators.Filtering.Backend -- | Implementation of filtering backend. class FilterBackend backend where { -- | The part of object which we are filtering on, provided by server -- backend implementor. type family AutoFilteredValue backend a; -- | A resulting predicate. type family MatchPredicate backend; } -- | Implementation of auto filter we provide. type AutoFilterImpl backend a = AutoFilteredValue backend a -> MatchPredicate backend -- | How to apply a filter - what server backend implementor provides. data FilteringApp backend param [AutoFilteringApp] :: Typeable a => AutoFilteredValue backend a -> FilteringApp backend ('TyNamedParam name ('AutoFilter a)) [ManualFilteringApp] :: Typeable a => (a -> MatchPredicate backend) -> FilteringApp backend ('TyNamedParam name ('ManualFilter a)) -- | Implementation of given auto filter type for Beam Postgres backend. class (Typeable filter, FilterBackend backend) => AutoFilterSupport backend filter a -- | Apply given filter to a value. autoFilterSupport :: AutoFilterSupport backend filter a => filter a -> AutoFilterImpl backend a -- | Enlists a way to apply each of supported filters at target application -- backend. type FilteringSpecApp backend params = HList (FilteringApp backend) params -- | Lookups for an appropriate filter application in a given -- FilteringSpecApp and applies it to a given filter. class FilterBackend backend => BackendApplySomeFilter backend (params :: [TyNamedFilter]) -- | Safely choose an appropriate filter from supported ones and prepare it -- for application. typeAutoFiltersSupport :: forall backend a. TypeAutoFiltersSupport backend a => SomeTypeAutoFilter a -> AutoFilterImpl backend a -- | Applies multiple filters to a set of response fields which matter for -- filtering. backendApplyFilters :: forall backend params. BackendApplySomeFilter backend params => FilteringSpec params -> FilteringSpecApp backend params -> [MatchPredicate backend] -- | Implement an automatic filter. User-provided filtering operation will -- do filter on this value. filterOn :: forall name backend a. Typeable a => AutoFilteredValue backend a -> FilteringApp backend ('TyNamedParam name ('AutoFilter a)) -- | Implement a manual filter. You are provided with a value which user -- supplied and so you have to construct a Beam predicate involving that -- value and relevant response fields. manualFilter :: forall name backend a. Typeable a => (a -> MatchPredicate backend) -> FilteringApp backend ('TyNamedParam name ('ManualFilter a)) instance forall k (backend :: k). Servant.Util.Combinators.Filtering.Backend.FilterBackend backend => Servant.Util.Combinators.Filtering.Backend.BackendApplySomeFilter backend '[] instance forall k (fk :: * -> Servant.Util.Combinators.Filtering.Base.FilterKind *) a (backend :: k) (name :: GHC.Types.Symbol) (params :: [Servant.Util.Combinators.Filtering.Base.TyNamedFilter]). (Data.Typeable.Internal.Typeable fk, Data.Typeable.Internal.Typeable a, Servant.Util.Combinators.Filtering.Backend.FilterBackend backend, GHC.TypeLits.KnownSymbol name, Servant.Util.Combinators.Filtering.Backend.BackendApplyTypeFilter backend fk a, Servant.Util.Combinators.Filtering.Backend.BackendApplySomeFilter backend params) => Servant.Util.Combinators.Filtering.Backend.BackendApplySomeFilter backend ('Servant.Util.Common.PolyKinds.TyNamedParam name (fk a) : params) instance forall k (backend :: k) a. Servant.Util.Combinators.Filtering.Backend.TypeAutoFiltersSupport backend a => Servant.Util.Combinators.Filtering.Backend.BackendApplyTypeFilter backend 'Servant.Util.Combinators.Filtering.Base.AutoFilter a instance forall k (backend :: k) a. Servant.Util.Combinators.Filtering.Backend.BackendApplyTypeFilter backend 'Servant.Util.Combinators.Filtering.Base.ManualFilter a instance forall k (backend :: k) a. Servant.Util.Combinators.Filtering.Backend.TypeAutoFiltersSupport' backend '[] a instance forall k (backend :: k) (filter :: * -> *) a (filters :: [* -> *]). (Servant.Util.Combinators.Filtering.Backend.AutoFilterSupport backend filter a, Servant.Util.Combinators.Filtering.Backend.TypeAutoFiltersSupport' backend filters a) => Servant.Util.Combinators.Filtering.Backend.TypeAutoFiltersSupport' backend (filter : filters) a module Servant.Util.Combinators.ErrorResponses -- | Type-level information about an error response. data ErrorDesc ErrorDesc :: Nat -> Type -> Symbol -> ErrorDesc [erCode] :: ErrorDesc -> Nat [erException] :: ErrorDesc -> Type [erDesc] :: ErrorDesc -> Symbol -- | Like ErrorDesc, but without exception type yet. data ErrorPartialDesc ErrorPartialDesc :: Nat -> Symbol -> ErrorPartialDesc [epdCode] :: ErrorPartialDesc -> Nat [epdDesc] :: ErrorPartialDesc -> Symbol -- | This combinator adds description of error response to swagger -- specification. -- -- You have two ways to define this combinator: -- --
-- ErrorResponses -- '[ 404 #! MyBackendException $ -- "Not found" -- , 403 #! Int $ -- "Operation is not permitted" -- ] ---- --
-- ExceptionalResponses MyBackendException -- '[ 404 #: "Not found" -- , 403 #: "Operation is not permitted" -- ] ---- -- Note that if an error code was already defined further in endpoint -- definition, it will be overwriten. For instance, Captures -- define 400 error code (invalid format); but in endpoint like -- ErrorResponses (400 ...) :> Capture ... :> ... -- description for 400-error case provided by Capture will be -- overwritten. -- -- This combinator is transparent for server implementation. data ErrorResponses (errs :: [ErrorDesc]) -- | A convenient alias for use with ExceptionalResponse. type (#:) = 'ErrorPartialDesc -- | Infix application. -- --
-- f :: Either String $ Maybe Int -- = -- f :: Either String (Maybe Int) --type (f :: k1 -> k) $ (a :: k1) = f a infixr 2 $ -- | An alias for ErrorResponse which allows to mention an -- exception type just once across all errors specification. type ExceptionalResponses err codes = ErrorResponses $ ExceptionDesc err codes instance Servant.Util.Combinators.ErrorResponses.KnownErrorCodes '[] instance (GHC.TypeNats.KnownNat code, GHC.TypeLits.KnownSymbol desc, Data.Swagger.Internal.Schema.ToSchema exc, Servant.Util.Combinators.ErrorResponses.KnownErrorCodes es) => Servant.Util.Combinators.ErrorResponses.KnownErrorCodes ('Servant.Util.Combinators.ErrorResponses.ErrorDesc code exc desc : es) instance (Servant.Swagger.Internal.HasSwagger subApi, Servant.Util.Combinators.ErrorResponses.KnownErrorCodes errors) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.ErrorResponses.ErrorResponses errors Servant.API.Sub.:> subApi) instance Servant.Server.Internal.HasServer subApi ctx => Servant.Server.Internal.HasServer (Servant.Util.Combinators.ErrorResponses.ErrorResponses errors Servant.API.Sub.:> subApi) ctx instance Servant.Client.Core.HasClient.HasClient m subApi => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.ErrorResponses.ErrorResponses errors Servant.API.Sub.:> subApi) instance Servant.Util.Combinators.Logging.HasLoggingServer config lcontext subApi ctx => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.Util.Combinators.ErrorResponses.ErrorResponses errors Servant.API.Sub.:> subApi) ctx -- | Implements plain filtering. -- -- Example: -- --
-- filteringSpecApp -- :: MyObject -- -> FilteringSpecApp -- DummyFilteringBackend -- [ "id" ?: 'AutoFilter Course -- , "desc" ?: 'AutoFilter Text -- , "isAwesome" ?: 'ManualFilter Bool -- ] -- filteringSpecApp obj = -- filterOn_ "id" (id obj) .*. -- filterOn_ "desc" (desc obj) .*. -- customFilter_ @"isAwesome" (== (awesomeness obj > 42)) .*. -- HNil ---- -- Annotating filterOn and customFilter calls with -- parameter name is fully optional and used only to visually -- disambiguate filters of the same types. -- -- Next, you use matches to check whether a value matches -- user-provided filters. -- --
-- filterObjects filters = filter (matches filters . filteringSpecApp) allObjects --module Servant.Util.Dummy.Filtering -- | Applies a whole filtering specification to a set of response fields. -- Resulting value can be put to filter function. matches :: (backend ~ DummyFilteringBackend, BackendApplySomeFilter backend params) => FilteringSpec params -> FilteringSpecApp backend params -> Bool -- | Filters given values by a filtering specification. filterBySpec :: (backend ~ DummyFilteringBackend, BackendApplySomeFilter backend params) => FilteringSpec params -> (a -> FilteringSpecApp backend params) -> [a] -> [a] -- | Implement an automatic filter. User-provided filtering operation will -- do filter on this value. filterOn :: forall name backend a. Typeable a => AutoFilteredValue backend a -> FilteringApp backend ('TyNamedParam name ('AutoFilter a)) -- | Implement a manual filter. You are provided with a value which user -- supplied and so you have to construct a Beam predicate involving that -- value and relevant response fields. manualFilter :: forall name backend a. Typeable a => (a -> MatchPredicate backend) -> FilteringApp backend ('TyNamedParam name ('ManualFilter a)) instance Servant.Util.Combinators.Filtering.Backend.FilterBackend Servant.Util.Dummy.Filtering.DummyFilteringBackend instance GHC.Classes.Eq a => Servant.Util.Combinators.Filtering.Backend.AutoFilterSupport Servant.Util.Dummy.Filtering.DummyFilteringBackend Servant.Util.Combinators.Filtering.Filters.General.FilterMatching a instance GHC.Classes.Ord a => Servant.Util.Combinators.Filtering.Backend.AutoFilterSupport Servant.Util.Dummy.Filtering.DummyFilteringBackend Servant.Util.Combinators.Filtering.Filters.General.FilterComparing a instance Universum.String.Conversion.ToString s => Servant.Util.Combinators.Filtering.Backend.AutoFilterSupport Servant.Util.Dummy.Filtering.DummyFilteringBackend Servant.Util.Combinators.Filtering.Filters.Like.FilterLike s -- | Implements plain lexicographical sorting. -- -- Example: -- --
-- sortingSpecApp -- :: MyObject -- -> SortingSpecApp -- DummySortingBackend -- [ "id" ?: Int -- , "desc" ?: Text -- ] -- sortingSpecApp obj = -- fieldSort "id" (id obj) .*. -- fieldSort "desc" (desc obj) .*. -- HNil ---- -- Next, you use sortBySpec to apply sorting. -- --
-- sortObjects sorting = filter (sortBySpec sorting . sortingSpecApp) allObjects --module Servant.Util.Dummy.Sorting -- | List of SortingApp functions. Describes how to apply -- SortingSpec params (each of possible SortingItem) to -- an SQL query. -- -- Instance of this type can be created using fieldSort function. -- For example: -- --
-- sortingSpecApp :: SortingSpecApp ["course" ?: Course, "desc" ?: Text] -- sortingSpecApp = -- fieldSort "course" courseField .*. -- fieldSort "desc" descField .*. -- HNil ---- -- Annotating fieldSort call with parameter name is not mandatory -- but recommended to prevent possible mistakes in fieldSorts -- ordering. type SortingSpecApp backend (allParams :: [TyNamedParam *]) = HList (SortingApp backend) allParams fieldSort :: forall name a backend. (SortingBackend backend, SortedValueConstraint backend a) => SortedValue backend a -> SortingApp backend ('TyNamedParam name a) -- | Applies a whole filtering specification to a set of response fields. -- Resulting value can be put to filter function. sortBySpec :: (backend ~ DummySortingBackend, allParams ~ AllSortingParams provided base, ApplyToSortItem backend allParams) => SortingSpec provided base -> (a -> SortingSpecApp backend allParams) -> [a] -> [a] instance GHC.Classes.Eq Servant.Util.Dummy.Sorting.SomeOrd instance GHC.Classes.Ord Servant.Util.Dummy.Sorting.SomeOrd instance Servant.Util.Combinators.Sorting.Backend.SortingBackend Servant.Util.Dummy.Sorting.DummySortingBackend -- | Errors in servant. module Servant.Util.Error -- | Custom json marker which sends no human-unreadable decoding errors but -- a given fixed one. data SimpleJSON err instance Servant.API.ContentTypes.Accept (Servant.Util.Error.SimpleJSON err) instance Data.Aeson.Types.ToJSON.ToJSON a => Servant.API.ContentTypes.MimeRender (Servant.Util.Error.SimpleJSON err) a instance (Data.Aeson.Types.FromJSON.FromJSON a, Data.Reflection.Reifies err GHC.Base.String) => Servant.API.ContentTypes.MimeUnrender (Servant.Util.Error.SimpleJSON err) a module Servant.Util.Internal.Util newtype Positive a PositiveUnsafe :: a -> Positive a [unPositive] :: Positive a -> a toPositive :: (Show a, Ord a, Num a) => a -> Either Text (Positive a) unsafeToPositive :: (Show a, Ord a, Num a, HasCallStack) => a -> Positive a type family IsNotZero (k :: Nat) :: Constraint type KnownPositive k = (KnownNat k, IsNotZero k) positiveVal :: forall k i. (KnownPositive k, Num i) => Positive i instance GHC.Classes.Ord a => GHC.Classes.Ord (Servant.Util.Internal.Util.Positive a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Servant.Util.Internal.Util.Positive a) instance GHC.Show.Show a => GHC.Show.Show (Servant.Util.Internal.Util.Positive a) instance Formatting.Buildable.Buildable x => Formatting.Buildable.Buildable (Servant.Util.Internal.Util.Positive x) instance (Web.Internal.HttpApiData.FromHttpApiData a, GHC.Show.Show a, GHC.Classes.Ord a, GHC.Num.Num a) => Web.Internal.HttpApiData.FromHttpApiData (Servant.Util.Internal.Util.Positive a) instance Web.Internal.HttpApiData.ToHttpApiData a => Web.Internal.HttpApiData.ToHttpApiData (Servant.Util.Internal.Util.Positive a) -- | Provides pagination API combinator. module Servant.Util.Combinators.Pagination -- | API combinator which enables pagination. -- -- Pagination parameters are specified via offset and -- limit query parameters. Both fields are optional; -- offset defaults to 0 and default value of -- limit is defined in settings argument. -- -- Your endpoint implementation will be provided with -- PaginationSpec variable which will contain parameters provided -- by the user. data PaginationParams (settings :: PaginationPageSize) -- | Determines the page size used when client leaves it unspecified. data PaginationPageSize -- | Use specified default. DefPageSize :: Nat -> PaginationPageSize -- | Display all contents. DefUnlimitedPageSize :: PaginationPageSize class KnownPaginationPageSize (settings :: PaginationPageSize) -- | Contains pagination parameters provided by the user. data PaginationSpec PaginationSpec :: Natural -> Maybe (Positive Natural) -> PaginationSpec -- | How many elements to skip. [psOffset] :: PaginationSpec -> Natural -- | Maximum number of elements to leave. Nothing stands for -- infinity. [psLimit] :: PaginationSpec -> Maybe (Positive Natural) -- | Do not paginate anything, use default page size. defPageSize :: PaginationSpec -- | Conveient builder for PaginationRequest, creates pagination -- with zero offset and given limit. itemsOnPage :: HasCallStack => Natural -> PaginationSpec -- | Convenient builder for PaginationRequest, modifies offset. skipping :: Natural -> PaginationSpec -> PaginationSpec -- | Do not paginate anything. -- | Deprecated: Use defPageSize instead fullContent :: PaginationSpec instance (Servant.Server.Internal.HasServer subApi ctx, Servant.Server.Internal.Context.HasContextEntry (ctx Servant.Server.Internal.Context..++ Servant.Server.Internal.ErrorFormatter.DefaultErrorFormatters) Servant.Server.Internal.ErrorFormatter.ErrorFormatters, Servant.Util.Combinators.Pagination.KnownPaginationPageSize settings) => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Pagination.PaginationParams settings Servant.API.Sub.:> subApi) ctx instance Servant.Client.Core.HasClient.HasClient m subApi => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.Pagination.PaginationParams settings Servant.API.Sub.:> subApi) instance Servant.Util.Internal.Util.KnownPositive pageSize => Servant.Util.Combinators.Pagination.KnownPaginationPageSize ('Servant.Util.Combinators.Pagination.DefPageSize pageSize) instance Servant.Util.Combinators.Pagination.KnownPaginationPageSize 'Servant.Util.Combinators.Pagination.DefUnlimitedPageSize instance (Servant.Util.Combinators.Logging.HasLoggingServer config lcontext subApi ctx, Servant.Util.Combinators.Pagination.KnownPaginationPageSize settings, Servant.Server.Internal.Context.HasContextEntry (ctx Servant.Server.Internal.Context..++ Servant.Server.Internal.ErrorFormatter.DefaultErrorFormatters) Servant.Server.Internal.ErrorFormatter.ErrorFormatters) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.Util.Combinators.Pagination.PaginationParams settings Servant.API.Sub.:> subApi) ctx instance (Servant.Swagger.Internal.HasSwagger api, Servant.Util.Combinators.Pagination.KnownPaginationPageSize settings) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Pagination.PaginationParams settings Servant.API.Sub.:> api) instance Data.Default.Class.Default Servant.Util.Combinators.Pagination.PaginationSpec module Servant.Util.Dummy.Pagination paginate :: PaginationSpec -> [a] -> [a] -- | Contains dummy backend implementations for introduced combinators. module Servant.Util.Dummy -- | Verious information about your API. module Servant.Util.Stats -- | For the given list of methods, ensure only they are used in API, and -- get corresponding Method terms. -- -- A primary use case for this function is specifying CORS methods where -- we need to think about each single method we allow, thus expecting -- methods list to be specified manually. methodsCoveringAPI :: forall methods api. (ContainsOnlyMethods methods api, ReflectMethods methods) => [Method] instance Servant.Util.Stats.ReflectMethods '[] instance (Servant.API.Verbs.ReflectMethod m, Servant.Util.Stats.ReflectMethods ms) => Servant.Util.Stats.ReflectMethods (m : ms) module Servant.Util.Swagger -- | Description of parameter. -- -- Unfortunatelly, servant-swagger package, when deriving -- description of an endpoint parameter, fills its description for you -- and makes you implement just ParamSchema which has no -- description field. To circumvent that you can define description in -- instance of this type family and later override swagger derivation -- accordingly. type family ParamDescription a :: Symbol type DescribedParam a = (ToParamSchema a, KnownSymbol (ParamDescription a)) -- | Set description according to ParamDescription definition. paramDescription :: forall a proxy. KnownSymbol (ParamDescription a) => proxy a -> Text -- | Defines swagger description for the given QueryFlag parameter. type family QueryFlagDescription (name :: Symbol) :: Symbol -- | This applies following transformations to API for the sake of better -- swagger documentation. -- --