@@ -228,7 +228,7 @@ class ToForm a where
228 -- | Convert a value into 'Form'.
228 -- | Convert a value into 'Form'.
229 toForm :: a -> Form
229 toForm :: a -> Form
230 default toForm :: (Generic a, GToForm a (Rep a)) => a -> Form
230 default toForm :: (Generic a, GToForm a (Rep a)) => a -> Form
231− toForm = genericToForm
231+ toForm = genericToForm defaultFormOptions
233instance ToForm Form where toForm = id
233instance ToForm Form where toForm = id
@@ -274,25 +274,25 @@ type family NotSupported (cls :: k1) (a :: k2) (reason :: Symbol) :: Constraint
274-- , age :: Int
274-- , age :: Int
275-- } deriving ('Generic')
275-- } deriving ('Generic')
277−genericToForm :: forall a. (Generic a, GToForm a (Rep a)) => a -> Form
277+genericToForm :: forall a. (Generic a, GToForm a (Rep a)) => FormOptions -> a -> Form
278−genericToForm = gToForm (Proxy :: Proxy a) . from
278+genericToForm opts = gToForm (Proxy :: Proxy a) opts . from
280class GToForm t (f :: * -> *) where
280class GToForm t (f :: * -> *) where
281− gToForm :: Proxy t -> f x -> Form
281+ gToForm :: Proxy t -> FormOptions -> f x -> Form
283instance (GToForm t f, GToForm t g) => GToForm t (f :*: g) where
283instance (GToForm t f, GToForm t g) => GToForm t (f :*: g) where
284− gToForm p (a :*: b) = gToForm p a <> gToForm p b
284+ gToForm p opts (a :*: b) = gToForm p opts a <> gToForm p opts b
286instance (GToForm t f) => GToForm t (M1 D x f) where
286instance (GToForm t f) => GToForm t (M1 D x f) where
287− gToForm p (M1 a) = gToForm p a
287+ gToForm p opts (M1 a) = gToForm p opts a
289instance (GToForm t f) => GToForm t (M1 C x f) where
289instance (GToForm t f) => GToForm t (M1 C x f) where
290− gToForm p (M1 a) = gToForm p a
290+ gToForm p opts (M1 a) = gToForm p opts a
292instance (Selector s, ToHttpApiData c) => GToForm t (M1 S s (K1 i c)) where
292instance (Selector s, ToHttpApiData c) => GToForm t (M1 S s (K1 i c)) where
293− gToForm _ (M1 (K1 c)) = fromList [(key, toQueryParam c)]
293+ gToForm _ opts (M1 (K1 c)) = fromList [(key, toQueryParam c)]
295− key = Text.pack $ selName (Proxy3 :: Proxy3 s g p)
295+ key = Text.pack $ fieldLabelModifier opts $ selName (Proxy3 :: Proxy3 s g p)
297instance NotSupported ToForm t "is a sum type" => GToForm t (f :+: g) where gToForm = error "impossible"
297instance NotSupported ToForm t "is a sum type" => GToForm t (f :+: g) where gToForm = error "impossible"
@@ -335,7 +335,7 @@ class FromForm a where
335 -- | Parse 'Form' into a value.
335 -- | Parse 'Form' into a value.
336 fromForm :: Form -> Either Text a
336 fromForm :: Form -> Either Text a
337 default fromForm :: (Generic a, GFromForm a (Rep a)) => Form -> Either Text a
337 default fromForm :: (Generic a, GFromForm a (Rep a)) => Form -> Either Text a
338− fromForm = genericFromForm
338+ fromForm = genericFromForm defaultFormOptions
340instance FromForm Form where fromForm = pure
340instance FromForm Form where fromForm = pure
@@ -371,25 +371,25 @@ toEntriesByKey = traverse parseGroup . HashMap.toList . unForm
371-- , age :: Int
371-- , age :: Int
372-- } deriving ('Generic')
372-- } deriving ('Generic')
374−genericFromForm :: forall a. (Generic a, GFromForm a (Rep a)) => Form -> Either Text a
374+genericFromForm :: forall a. (Generic a, GFromForm a (Rep a)) => FormOptions -> Form -> Either Text a
375−genericFromForm f = to <$> gFromForm (Proxy :: Proxy a) f
375+genericFromForm opts f = to <$> gFromForm (Proxy :: Proxy a) opts f
377class GFromForm t (f :: * -> *) where
377class GFromForm t (f :: * -> *) where
378− gFromForm :: Proxy t -> Form -> Either Text (f x)
378+ gFromForm :: Proxy t -> FormOptions -> Form -> Either Text (f x)
380instance (GFromForm t f, GFromForm t g) => GFromForm t (f :*: g) where
380instance (GFromForm t f, GFromForm t g) => GFromForm t (f :*: g) where
381− gFromForm p f = (:*:) <$> gFromForm p f <*> gFromForm p f
381+ gFromForm p opts f = (:*:) <$> gFromForm p opts f <*> gFromForm p opts f
383instance (Selector s, FromHttpApiData f) => GFromForm t (M1 S s (K1 i f)) where
383instance (Selector s, FromHttpApiData f) => GFromForm t (M1 S s (K1 i f)) where
384− gFromForm _ form = M1 . K1 <$> parseUnique key form
384+ gFromForm _ opts form = M1 . K1 <$> parseUnique key form
386− key = Text.pack $ selName (Proxy3 :: Proxy3 s g p)
386+ key = Text.pack $ fieldLabelModifier opts $ selName (Proxy3 :: Proxy3 s g p)
388instance GFromForm t f => GFromForm t (M1 D x f) where
388instance GFromForm t f => GFromForm t (M1 D x f) where
389− gFromForm p f = M1 <$> gFromForm p f
389+ gFromForm p opts f = M1 <$> gFromForm p opts f
391instance GFromForm t f => GFromForm t (M1 C x f) where
391instance GFromForm t f => GFromForm t (M1 C x f) where
392− gFromForm p f = M1 <$> gFromForm p f
392+ gFromForm p opts f = M1 <$> gFromForm p opts f
394instance NotSupported FromForm t "is a sum type" => GFromForm t (f :+: g) where gFromForm = error "impossible"
394instance NotSupported FromForm t "is a sum type" => GFromForm t (f :+: g) where gFromForm = error "impossible"
@@ -551,3 +551,20 @@ parseAll key = parseQueryParams . lookupAll key
551parseUnique :: FromHttpApiData v => Text -> Form -> Either Text v
551parseUnique :: FromHttpApiData v => Text -> Form -> Either Text v
552parseUnique key form = lookupUnique key form >>= parseQueryParam
552parseUnique key form = lookupUnique key form >>= parseQueryParam
554+-- | 'Generic'-based deriving options for 'ToForm' and 'FromForm'.
555+data FormOptions = FormOptions
556+ { -- | Function applied to field labels. Handy for removing common record prefixes for example.
557+ fieldLabelModifier :: String -> String
560+-- | Default encoding 'FormOptions'.
564+-- { 'fieldLabelModifier' = id
567+defaultFormOptions :: FormOptions
568+defaultFormOptions = FormOptions
569+ { fieldLabelModifier = id