-- 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 -- -- -- -- If user makes request which is not defined it won't be logged. -- However, I don't find it a great problem, it may impede only in -- development or on getting acknowledged with api. data LoggingApi config api -- | Helper to traverse servant api and apply logging. data LoggingApiRec config (lcontext :: LoggingContext) api -- | Servant combinator that changes how the logs will be printed for the -- affected endpoints. -- -- This is an internal thing, we export aliases. data LoggingMod (mod :: LoggingModKind) -- | Combinator to set the logging level within the endpoints. type LoggingLevel lvl = LoggingMod ('LMLoggingLevel lvl) -- | Combinator to enable logging of requests back for a narrower set of -- entrypoints. type LoggingRequestsEnabled = LoggingMod ('LMRequestsLogged 'True) -- | Combinator to disable logging of requests. type LoggingRequestsDisabled = LoggingMod ('LMRequestsLogged 'False) -- | Combinator to enable logging of responses. type LoggingResponsesEnabled = LoggingMod ('LMResponsesLogged 'True) -- | Combinator to disable logging of responses. type LoggingResponsesDisabled = LoggingMod ('LMResponsesLogged 'False) -- | Combinator to disable all the logging. -- -- This works similarly to other similar combinators and can be partially -- or fully reverted with LoggingRequestsDisabled or -- LoggingResponsesDisabled. type LoggingDisabled = LoggingMod 'LMLoggingDisabled -- | Logging context that will be supplied to the user. newtype LogContext LogContext :: Maybe Natural -> LogContext -- | Logging level specified by LoggingLevel combinator. [lecRecommendedLevel] :: LogContext -> Maybe Natural -- | Version of HasServer which is assumed to perform logging. It's -- helpful because 'ServerT (LoggingApi ...)' is already defined for us -- in actual HasServer instance once and forever. class HasServer api ctx => HasLoggingServer config (lcontext :: LoggingContext) api ctx routeWithLog :: HasLoggingServer config lcontext api ctx => Proxy (LoggingApiRec config lcontext api) -> Context ctx -> Delayed env (Server (LoggingApiRec config lcontext api)) -> Router env -- | Logging configuration specified at server start. newtype ServantLogConfig ServantLogConfig :: (LogContext -> Text -> IO ()) -> ServantLogConfig [clcLog] :: ServantLogConfig -> LogContext -> Text -> IO () -- | When it comes to logging responses, returned data may be very large. -- Log space is valuable (already in testnet we got truncated logs), so -- we have to care about printing only whose data which may be useful. newtype ForResponseLog a ForResponseLog :: a -> ForResponseLog a [unForResponseLog] :: ForResponseLog a -> a -- | Require Buildable for the response type, but only if logging -- context assumes that the response will indeed be built. type BuildableForResponseIfNecessary lcontext resp = (If (LcResponsesEnabled lcontext) (Buildable (ForResponseLog resp)) (() :: Constraint), Demote (LcResponsesEnabled lcontext)) buildListForResponse :: Buildable (ForResponseLog x) => (forall a. [a] -> [a]) -> ForResponseLog [x] -> Builder buildForResponse :: Buildable a => ForResponseLog a -> Builder -- | 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 -- | Describes a way to log a single parameter. class ApiHasArgClass subApi => ApiCanLogArg subApi where { type family ApiArgToLog subApi :: Type; type ApiArgToLog subApi = ApiArg subApi; } toLogParamInfo :: (ApiCanLogArg subApi, Buildable (ApiArgToLog subApi)) => Proxy subApi -> ApiArg subApi -> Text toLogParamInfo :: (ApiCanLogArg subApi, Buildable (ApiArg subApi)) => Proxy subApi -> ApiArg subApi -> Text addParamLogInfo :: Text -> ApiParamsLogInfo -> ApiParamsLogInfo setInPrefix :: ApiParamsLogInfo -> ApiParamsLogInfo -- | Apply logging to the given server. serverWithLogging :: forall api a. ServantLogConfig -> Proxy api -> (forall (config :: Type). Reifies config ServantLogConfig => Proxy (LoggingApi config api) -> a) -> a instance GHC.Show.Show Servant.Util.Combinators.Logging.LogFullContext instance GHC.Classes.Eq Servant.Util.Combinators.Logging.LogContext instance GHC.Show.Show Servant.Util.Combinators.Logging.LogContext instance Formatting.Buildable.Buildable Servant.Util.Combinators.Logging.RequestId instance GHC.TypeLits.KnownSymbol s => Servant.Util.Combinators.Logging.ApiCanLogArg (Servant.API.Capture.Capture s a) instance Servant.Util.Combinators.Logging.ApiCanLogArg (Servant.API.ReqBody.ReqBody ct a) instance (Formatting.Buildable.Buildable a, GHC.TypeLits.KnownSymbol cs, Data.Singletons.Bool.SBoolI (Servant.API.Modifiers.FoldRequired mods)) => Servant.Util.Combinators.Logging.ApiCanLogArg (Servant.API.QueryParam.QueryParam' mods cs a) instance GHC.TypeLits.KnownSymbol cs => Servant.Util.Combinators.Logging.ApiCanLogArg (Servant.API.QueryParam.QueryFlag cs) instance forall k subApi res (ctx :: [*]) (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) (apiType :: * -> *) a. (Servant.Server.Internal.HasServer (subApi Servant.API.Sub.:> res) ctx, Servant.Server.Internal.HasServer (subApi Servant.API.Sub.:> Servant.Util.Combinators.Logging.LoggingApiRec config lcontext res) ctx, Servant.Util.Common.Common.ApiHasArg subApi res, Servant.Util.Common.Common.ApiHasArg subApi (Servant.Util.Combinators.Logging.LoggingApiRec config lcontext res), Servant.Util.Combinators.Logging.ApiCanLogArg subApi, Formatting.Buildable.Buildable (Servant.Util.Combinators.Logging.ApiArgToLog subApi), subApi GHC.Types.~ apiType a) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (apiType a Servant.API.Sub.:> res) ctx instance forall k1 k2 (config :: k1) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) (api :: k2) (ctx :: [*]). Servant.Util.Combinators.Logging.HasLoggingServer config lcontext api ctx => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Logging.LoggingApiRec config lcontext api) ctx instance forall k (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) api1 (ctx :: [*]) api2. (Servant.Util.Combinators.Logging.HasLoggingServer config lcontext api1 ctx, Servant.Util.Combinators.Logging.HasLoggingServer config lcontext api2 ctx) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (api1 Servant.API.Alternative.:<|> api2) ctx instance forall k (path :: GHC.Types.Symbol) (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) res (ctx :: [*]). (GHC.TypeLits.KnownSymbol path, Servant.Util.Combinators.Logging.HasLoggingServer config lcontext res ctx) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (path Servant.API.Sub.:> res) ctx instance forall k (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) res (ctx :: [*]) (s :: GHC.Types.Symbol). (Servant.Util.Combinators.Logging.HasLoggingServer config lcontext res ctx, GHC.TypeLits.KnownSymbol s) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.API.QueryParam.QueryFlag s Servant.API.Sub.:> res) ctx instance forall k (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) res (ctx :: [*]) (s :: GHC.Types.Symbol). Servant.Util.Combinators.Logging.HasLoggingServer config lcontext res ctx => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.API.Description.Summary s Servant.API.Sub.:> res) ctx instance forall k (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) res (ctx :: [*]) (d :: GHC.Types.Symbol). Servant.Util.Combinators.Logging.HasLoggingServer config lcontext res ctx => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.API.Description.Description d Servant.API.Sub.:> res) ctx instance forall k (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) (mod :: Servant.Util.Combinators.Logging.LoggingModKind) res (ctx :: [*]). (Servant.Util.Combinators.Logging.HasLoggingServer config (Servant.Util.Combinators.Logging.ApplyLoggingMod lcontext mod) res ctx, Servant.Server.Internal.HasServer res ctx) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.Util.Combinators.Logging.LoggingMod mod Servant.API.Sub.:> res) ctx instance forall k1 k2 (mt :: k2) (st :: GHC.Types.Nat) (ct :: [*]) a (ctx :: [*]) (config :: k1) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext). (Servant.Server.Internal.HasServer (Servant.API.Verbs.Verb mt st ct a) ctx, Data.Reflection.Reifies config Servant.Util.Combinators.Logging.ServantLogConfig, Servant.Util.Common.PolyKinds.Demote lcontext, Servant.API.Verbs.ReflectMethod mt, Servant.Util.Combinators.Logging.BuildableForResponseIfNecessary lcontext a) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.API.Verbs.Verb mt st ct a) ctx instance forall k1 k2 (mt :: k2) (ctx :: [*]) (config :: k1) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext). (Servant.Server.Internal.HasServer (Servant.API.Verbs.NoContentVerb mt) ctx, Data.Reflection.Reifies config Servant.Util.Combinators.Logging.ServantLogConfig, Servant.Util.Common.PolyKinds.Demote lcontext, Servant.API.Verbs.ReflectMethod mt, Servant.Util.Combinators.Logging.BuildableForResponseIfNecessary lcontext Servant.API.ContentTypes.NoContent) => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.API.Verbs.NoContentVerb mt) ctx instance forall k (config :: k) (lcontext :: Servant.Util.Combinators.Logging.LoggingContext) (ctx :: [*]). Servant.Util.Combinators.Logging.HasLoggingServer config lcontext Servant.API.Raw.Raw ctx instance Formatting.Buildable.Buildable (Servant.Util.Combinators.Logging.ForResponseLog Servant.API.ContentTypes.NoContent) instance Formatting.Buildable.Buildable (Servant.Util.Combinators.Logging.ForResponseLog ()) instance Formatting.Buildable.Buildable (Servant.Util.Combinators.Logging.ForResponseLog GHC.Integer.Type.Integer) instance Formatting.Buildable.Buildable (Servant.Util.Combinators.Logging.ForResponseLog Data.Swagger.Internal.Swagger) instance Formatting.Buildable.Buildable (Servant.Util.Combinators.Logging.ForResponseLog (Servant.Swagger.UI.Core.SwaggerUiHtml dir api)) instance Data.Default.Class.Default Servant.Util.Combinators.Logging.ApiParamsLogInfo instance (ctx GHC.Types.~ 'Servant.Util.Combinators.Logging.LoggingContext lvl req resp, Servant.Util.Common.PolyKinds.Demote lvl, Servant.Util.Common.PolyKinds.Demote req, Servant.Util.Common.PolyKinds.Demote resp) => Servant.Util.Common.PolyKinds.Demote ctx instance Servant.Server.Internal.HasServer api ctx => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Logging.LoggingMod mod Servant.API.Sub.:> api) ctx instance Servant.Client.Core.HasClient.HasClient m api => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.Logging.LoggingMod mod Servant.API.Sub.:> api) instance Servant.Swagger.Internal.HasSwagger api => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Logging.LoggingMod mod Servant.API.Sub.:> api) instance forall k1 k2 (config :: k1) (api :: k2) (ctx :: [*]). (Servant.Server.Internal.HasServer (Servant.Util.Combinators.Logging.LoggingApiRec config Servant.Util.Combinators.Logging.EmptyLoggingContext api) ctx, Servant.Server.Internal.HasServer api ctx) => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Logging.LoggingApi config api) ctx module Servant.Util.Combinators.Tag -- | Attaches a tag to swagger documentation. Server implementation remains -- intact. data Tag (name :: Symbol) -- | Attaches descriptions to tags according to the given name -> -- description mapping. Unused elements of mapping will cause a -- compile error; tags which have no mapping declared are not allowed as -- well. data TagDescriptions (verify :: TagsVerification) (mapping :: [TyNamedParam Symbol]) -- | Whether to enable some type-level checks for Tags and -- TagsDescriptions correspondence. data TagsVerification -- | Ensure that mappings are specified exactly for those tags which appear -- in API. This may slow down compilation dramatically starting from ~15 -- tags. VerifyTags :: TagsVerification -- | Do not check anything. NoVerifyTags :: TagsVerification instance Servant.Util.Combinators.Tag.ReifyTagsFromMapping '[] instance (GHC.TypeLits.KnownSymbol name, GHC.TypeLits.KnownSymbol desc, Servant.Util.Combinators.Tag.ReifyTagsFromMapping mapping, Servant.Util.Common.PolyKinds.ParamsContainNoName mapping name) => Servant.Util.Combinators.Tag.ReifyTagsFromMapping ('Servant.Util.Common.PolyKinds.TyNamedParam name desc : mapping) instance (Servant.Swagger.Internal.HasSwagger api, Servant.Util.Combinators.Tag.ReifyTagsFromMapping mapping) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Tag.TagDescriptions 'Servant.Util.Combinators.Tag.NoVerifyTags mapping Servant.API.Sub.:> api) instance (Servant.Swagger.Internal.HasSwagger api, Servant.Util.Combinators.Tag.ReifyTagsFromMapping mapping, missingMapping GHC.Types.~ (Servant.Util.Combinators.Tag.AllApiTags api Servant.Util.Common.PolyKinds.// Servant.Util.Common.PolyKinds.TyNamedParamsNames mapping), Data.Type.Bool.If (missingMapping Servant.Util.Common.PolyKinds.== '[]) (() :: Constraint) (TypeError ...), extraMapping GHC.Types.~ (Servant.Util.Common.PolyKinds.TyNamedParamsNames mapping Servant.Util.Common.PolyKinds.// Servant.Util.Combinators.Tag.AllApiTags api), Data.Type.Bool.If (extraMapping Servant.Util.Common.PolyKinds.== '[]) (() :: Constraint) (TypeError ...)) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Tag.TagDescriptions 'Servant.Util.Combinators.Tag.VerifyTags mapping Servant.API.Sub.:> api) instance Servant.Server.Internal.HasServer subApi ctx => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Tag.TagDescriptions ver mapping Servant.API.Sub.:> subApi) ctx instance Servant.Client.Core.HasClient.HasClient m subApi => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.Tag.TagDescriptions ver mapping Servant.API.Sub.:> subApi) instance Servant.Util.Combinators.Logging.HasLoggingServer config context subApi ctx => Servant.Util.Combinators.Logging.HasLoggingServer config context (Servant.Util.Combinators.Tag.TagDescriptions ver mapping Servant.API.Sub.:> subApi) ctx instance Servant.Server.Internal.HasServer subApi ctx => Servant.Server.Internal.HasServer (Servant.Util.Combinators.Tag.Tag name Servant.API.Sub.:> subApi) ctx instance Servant.Client.Core.HasClient.HasClient m subApi => Servant.Client.Core.HasClient.HasClient m (Servant.Util.Combinators.Tag.Tag name Servant.API.Sub.:> subApi) instance Servant.Util.Combinators.Logging.HasLoggingServer config lcontext subApi ctx => Servant.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.Util.Combinators.Tag.Tag name Servant.API.Sub.:> subApi) ctx instance (Servant.Swagger.Internal.HasSwagger subApi, GHC.TypeLits.KnownSymbol name) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Tag.Tag name Servant.API.Sub.:> subApi) module Servant.Util.Combinators.Sorting.Logging instance (Servant.Util.Combinators.Logging.HasLoggingServer config lcontext 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.Util.Combinators.Logging.HasLoggingServer config lcontext (Servant.Util.Combinators.Sorting.Base.SortingParams provided base Servant.API.Sub.:> subApi) ctx -- | Provides combinator for lexicographical sorting. module Servant.Util.Combinators.Sorting -- | 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 *)]) -- | 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. -- -- type family SwaggerrizeApi api instance (Servant.Swagger.Internal.HasSwagger subApi, GHC.TypeLits.KnownSymbol name, GHC.TypeLits.KnownSymbol (Servant.Util.Swagger.QueryFlagDescription name)) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Swagger.SwaggerQueryFlag name Servant.API.Sub.:> subApi) instance (Servant.Swagger.Internal.HasSwagger (Servant.API.QueryParam.QueryParam' mods sym a Servant.API.Sub.:> api), Servant.Swagger.Internal.HasSwagger api) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Swagger.SwaggerQueryParam mods sym a Servant.API.Sub.:> api) instance (Servant.Swagger.Internal.HasSwagger (Servant.API.Capture.Capture' mods sym a Servant.API.Sub.:> api), Servant.Swagger.Internal.HasSwagger api) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Swagger.SwaggerCapture mods sym a Servant.API.Sub.:> api) module Servant.Util.Combinators.Filtering.Swagger instance Servant.Util.Combinators.Filtering.Swagger.FilterParamsHaveSwagger '[] instance (GHC.TypeLits.KnownSymbol name, Servant.Util.Combinators.Filtering.Swagger.FilterKindHasSwagger fk, Servant.Util.Combinators.Filtering.Swagger.FilterParamsHaveSwagger params) => Servant.Util.Combinators.Filtering.Swagger.FilterParamsHaveSwagger ('Servant.Util.Common.PolyKinds.TyNamedParam name fk : params) instance (Servant.Swagger.Internal.HasSwagger api, Servant.Util.Common.PolyKinds.ReifyParamsNames params, Servant.Util.Combinators.Filtering.Swagger.FilterParamsHaveSwagger params) => Servant.Swagger.Internal.HasSwagger (Servant.Util.Combinators.Filtering.Base.FilteringParams params Servant.API.Sub.:> api) instance Servant.Util.Swagger.DescribedParam a => Servant.Util.Combinators.Filtering.Swagger.FilterKindHasSwagger ('Servant.Util.Combinators.Filtering.Base.ManualFilter a) instance (Servant.Util.Swagger.DescribedParam a, Servant.Util.Combinators.Filtering.Swagger.AutoFiltersOpsDesc (Servant.Util.Combinators.Filtering.Base.SupportedFilters a)) => Servant.Util.Combinators.Filtering.Swagger.FilterKindHasSwagger ('Servant.Util.Combinators.Filtering.Base.AutoFilter a) instance Servant.Util.Combinators.Filtering.Swagger.AutoFiltersOpsDesc '[] instance (Servant.Util.Combinators.Filtering.Base.IsAutoFilter filter, Servant.Util.Combinators.Filtering.Swagger.AutoFiltersOpsDesc filters) => Servant.Util.Combinators.Filtering.Swagger.AutoFiltersOpsDesc (filter : filters) -- | Allows complex filtering on specified fields. module Servant.Util.Combinators.Filtering -- | 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 -- | 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]) -- | 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) -- | 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 -- | Support for SQL's LIKE syntax. data FilterLike a FilterLike :: CaseSensitivity -> LikePattern -> FilterLike a -- | Simple regexp pattern, . and * signed will be -- considered. Escaping is performed via prefixing with backslash. newtype LikePattern LikePatternUnsafe :: LText -> LikePattern [unLikePattern] :: LikePattern -> LText type NumericFilterTypes = [FilterMatching, FilterComparing] type TextFilterTypes = [FilterMatching, FilterComparing, FilterLike] type DatetimeFilterTypes = '[FilterComparing] module Servant.Util.Combinators module Servant.Util -- | Some common utilities. module Servant.Util.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 positiveVal :: forall k i. (KnownPositive k, Num i) => Positive i