Skip to content

Commit 6fbfa06

Browse files
committed
can use ToQuery and FromQuery generics-based classes
1 parent 3001713 commit 6fbfa06

File tree

10 files changed

+310
-209
lines changed

10 files changed

+310
-209
lines changed

ghcjs/delivery-calculator/src/App/Types.hs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ data St f = St
101101
stTheme :: Theme
102102
}
103103
deriving stock (Generic)
104-
deriving (ToQuery) via GenericType (St f)
105104

106105
deriving stock instance (Hkt f) => Eq (St f)
107106

@@ -111,6 +110,10 @@ deriving stock instance (Hkt f) => Show (St f)
111110

112111
deriving stock instance (Hkt f) => Data (St f)
113112

113+
deriving via (GenericType (St f)) instance (Hkt f) => ToQuery (St f)
114+
115+
deriving via (GenericType (St Identity)) instance FromQuery (St Identity)
116+
114117
instance FunctorB St
115118

116119
instance TraversableB St
@@ -163,6 +166,12 @@ instance TraversableB Asset
163166

164167
deriving via GenericType (Asset Identity) instance Binary (Asset Identity)
165168

169+
instance ToQueryField [Asset f] where
170+
toQueryField _ = pure mempty
171+
172+
instance FromQueryField [Asset f] where
173+
fromQueryField _ _ = pure mempty
174+
166175
newAsset :: (MonadIO m, MonadThrow m) => m (Asset Unique)
167176
newAsset = do
168177
uid <- newUid
@@ -407,7 +416,10 @@ foldFieldPair acc =
407416
foldField acc . fieldPairValue
408417

409418
stShortUri :: (MonadThrow m) => Model -> m URI
410-
stShortUri = stUri . (#modelState . #stAssets .~ mempty)
419+
stShortUri st = do
420+
uri <- mkURI $ from @Unicode @Prelude.Text baseUri
421+
let qxs = toQuery . uniqueToIdentity $ modelState st
422+
pure $ uri {URI.uriQuery = qxs}
411423

412424
stLongUri :: (MonadThrow m) => Model -> m URI
413425
stLongUri = stUri

ghcjs/miso-functora/src/Functora/Miso/Orphan.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ import Data.Monoid.GCD
1010
import Data.Monoid.Null
1111
import Data.Monoid.Textual
1212
import Data.Semigroup.Cancellative
13+
import Functora.Miso.Theme (Theme)
1314
import Functora.Prelude
15+
import Functora.Uri
1416
import qualified Miso
1517
import Prelude hiding (String)
1618

19+
deriving via (GenericEnum Theme) instance ToQueryField Theme
20+
21+
deriving via (GenericEnum Theme) instance FromQueryField Theme
22+
1723
deriving stock instance Generic (Miso.View action)
1824

1925
deriving stock instance Generic (Miso.Attribute action)

ghcjs/miso-functora/src/Functora/Miso/Types.hs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type Typ a =
8787

8888
type Hkt f =
8989
( Typeable f,
90+
Foldable1 f,
9091
Eq (f Unicode),
9192
Ord (f Unicode),
9293
Show (f Unicode),
@@ -155,6 +156,26 @@ deriving via
155156
instance
156157
(Typ a) => Binary (Field a Identity)
157158

159+
instance (Foldable1 f) => ToQueryField (Field a f) where
160+
toQueryField = toQueryField . fold1 . fieldInput
161+
162+
instance FromQueryField (Field Rational Identity) where
163+
fromQueryField k v = do
164+
out <-
165+
first (const $ FromQueryInvalidField k v)
166+
. parseRatio
167+
$ URI.unRText v
168+
pure
169+
$ newFieldId
170+
FieldTypeNumber
171+
inspectRatioDef
172+
out
173+
174+
instance FromQueryField (Field Unicode Identity) where
175+
fromQueryField k v = do
176+
out <- castFromQueryField k v
177+
pure $ newFieldId FieldTypeText id out
178+
158179
data FieldOpts = FieldOpts
159180
{ fieldOptsAllowCopy :: Bool,
160181
fieldOptsTruncateLimit :: Maybe Int,
@@ -409,10 +430,25 @@ instance FunctorB Currency
409430

410431
instance TraversableB Currency
411432

412-
deriving via
413-
GenericType (Currency Identity)
414-
instance
415-
Binary (Currency Identity)
433+
deriving via GenericType (Currency Identity) instance Binary (Currency Identity)
434+
435+
instance ToQueryField (Currency f) where
436+
toQueryField =
437+
toQueryField
438+
. (^. #currencyOutput . #currencyInfoCode . #unCurrencyCode)
439+
440+
instance FromQueryField (Currency Identity) where
441+
fromQueryField _ v =
442+
pure
443+
Currency
444+
{ currencyInput = newTextFieldId mempty,
445+
currencyOutput =
446+
CurrencyInfo
447+
{ currencyInfoText = mempty,
448+
currencyInfoCode = CurrencyCode $ URI.unRText v
449+
},
450+
currencyModalState = Closed
451+
}
416452

417453
newCurrency :: (MonadIO m) => CurrencyInfo -> m (Currency Unique)
418454
newCurrency cur =
@@ -527,42 +563,49 @@ data TopOrBottom
527563
| Bottom
528564
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
529565
deriving (Binary) via GenericType TopOrBottom
566+
deriving (ToQueryField, FromQueryField) via GenericEnum TopOrBottom
530567

531568
data OnlineOrOffline
532569
= Online
533570
| Offline
534571
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
535572
deriving (Binary) via GenericType OnlineOrOffline
573+
deriving (ToQueryField, FromQueryField) via GenericEnum OnlineOrOffline
536574

537575
data StaticOrDynamic
538576
= Static
539577
| Dynamic
540578
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
541579
deriving (Binary) via GenericType StaticOrDynamic
580+
deriving (ToQueryField, FromQueryField) via GenericEnum StaticOrDynamic
542581

543582
data LeadingOrTrailing
544583
= Leading
545584
| Trailing
546585
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
547586
deriving (Binary) via GenericType LeadingOrTrailing
587+
deriving (ToQueryField, FromQueryField) via GenericEnum LeadingOrTrailing
548588

549589
data EnabledOrDisabled
550590
= Enabled
551591
| Disabled
552592
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
553593
deriving (Binary) via GenericType EnabledOrDisabled
594+
deriving (ToQueryField, FromQueryField) via GenericEnum EnabledOrDisabled
554595

555596
data FocusedOrBlurred
556597
= Focused
557598
| Blurred
558599
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
559600
deriving (Binary) via GenericType FocusedOrBlurred
601+
deriving (ToQueryField, FromQueryField) via GenericEnum FocusedOrBlurred
560602

561603
data OpenedOrClosed
562604
= Opened
563605
| Closed
564606
deriving stock (Eq, Ord, Show, Read, Enum, Bounded, Data, Generic)
565607
deriving (Binary) via GenericType OpenedOrClosed
608+
deriving (ToQueryField, FromQueryField) via GenericEnum OpenedOrClosed
566609

567610
data Update model
568611
= PureUpdate (model -> model)

pub/functora/functora.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ common pkg-uri
166166
, containers
167167
, modern-uri
168168
, tomland
169+
, universum
169170

170171
if ((impl(ghcjs) || arch(javascript)) || os(wasi))
171172
build-depends: jsaddle
@@ -182,7 +183,6 @@ common pkg-cfg
182183
, modern-uri
183184
, optparse-applicative
184185
, tomland
185-
, uri
186186

187187
common pkg-web
188188
import: pkg
Lines changed: 1 addition & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
{-# LANGUAGE UndecidableInstances #-}
2-
31
module Functora.Cfg
42
( module X,
53

@@ -22,11 +20,6 @@ module Functora.Cfg
2220
-- $binary
2321
decodeBinary,
2422
encodeBinary,
25-
26-
-- * DerivingVia
27-
-- $derivingVia
28-
GenericEnum (..),
29-
GenericType (..),
3023
)
3124
where
3225

@@ -43,10 +36,8 @@ import qualified Data.Binary.Get as Binary
4336
import Data.Binary.Instances as X ()
4437
import qualified Data.ByteString.Lazy as BL
4538
import qualified Data.List.NonEmpty as NE
46-
import Functora.CfgOrphan as X ()
39+
import Functora.CfgOrphan (genericTomlCodec)
4740
import Functora.Prelude
48-
import Functora.Uri
49-
import qualified GHC.Generics as Generics
5041
import qualified Options.Applicative as Cli
5142
import Toml as X
5243
( HasCodec,
@@ -160,21 +151,6 @@ encodeToml ::
160151
encodeToml =
161152
Toml.encode genericTomlCodec
162153

163-
genericTomlCodec ::
164-
( Generic a,
165-
Typeable a,
166-
Toml.GenericCodec (Rep a)
167-
) =>
168-
TomlCodec a
169-
genericTomlCodec =
170-
Toml.genericCodecWithOptions
171-
Toml.TomlOptions
172-
{ Toml.tomlOptionsFieldModifier = \proxy ->
173-
Toml.stripTypeNamePrefix proxy . \case
174-
('_' : xs) -> xs
175-
xs -> xs
176-
}
177-
178154
-- $binary
179155
-- Binary
180156

@@ -195,136 +171,3 @@ decodeBinary raw = do
195171

196172
encodeBinary :: (Binary a) => a -> BL.ByteString
197173
encodeBinary = Binary.encode
198-
199-
-- $derivingVia
200-
-- Newtypes to simplify deriving via.
201-
-- We have to expose default constructors/accessors
202-
-- to help GHC with figuring out that runtime representation does match.
203-
204-
newtype GenericEnum a = GenericEnum
205-
{ unGenericEnum :: a
206-
}
207-
deriving newtype (Show, Enum, Bounded)
208-
209-
instance (Show a, Enum a, Bounded a) => HasCodec (GenericEnum a) where
210-
hasCodec = Toml.enumBounded
211-
212-
instance (Show a, Enum a, Bounded a) => HasItemCodec (GenericEnum a) where
213-
hasItemCodec = Left Toml._EnumBounded
214-
215-
newtype GenericType a = GenericType
216-
{ unGenericType :: a
217-
}
218-
deriving stock (Generic)
219-
220-
instance
221-
( Generic a,
222-
Typeable a,
223-
GToQuery (Rep a)
224-
) =>
225-
ToQuery (GenericType a)
226-
where
227-
toQuery = genericToQuery . unGenericType
228-
229-
instance
230-
( Generic a,
231-
GFromQuery (Rep a)
232-
) =>
233-
FromQuery (GenericType a)
234-
where
235-
fromQuery = fmap GenericType . genericFromQuery
236-
237-
instance
238-
( Generic a,
239-
Typeable a,
240-
Toml.GenericCodec (Rep a)
241-
) =>
242-
HasCodec (GenericType a)
243-
where
244-
hasCodec = Toml.diwrap . Toml.table (genericTomlCodec @a)
245-
246-
instance
247-
( Generic a,
248-
Typeable a,
249-
Toml.GenericCodec (Rep a)
250-
) =>
251-
HasItemCodec (GenericType a)
252-
where
253-
hasItemCodec = Right . Toml.diwrap $ genericTomlCodec @a
254-
255-
instance
256-
( Generic a,
257-
Typeable a,
258-
A.GFromJSON A.Zero (Rep a)
259-
) =>
260-
FromJSON (GenericType a)
261-
where
262-
parseJSON = fmap GenericType . A.genericParseJSON (optsAeson @a)
263-
264-
instance
265-
( Generic a,
266-
Typeable a,
267-
A.GFromJSON A.Zero (Rep a),
268-
A.GFromJSONKey (Rep a)
269-
) =>
270-
FromJSONKey (GenericType a)
271-
where
272-
fromJSONKey = GenericType <$> A.genericFromJSONKey A.defaultJSONKeyOptions
273-
274-
instance
275-
( Generic a,
276-
Typeable a,
277-
A.GToJSON A.Zero (Rep a),
278-
A.GToEncoding A.Zero (Rep a)
279-
) =>
280-
ToJSON (GenericType a)
281-
where
282-
toJSON = A.genericToJSON (optsAeson @a) . unGenericType
283-
toEncoding = A.genericToEncoding (optsAeson @a) . unGenericType
284-
285-
instance
286-
( Generic a,
287-
Typeable a,
288-
A.GToJSON A.Zero (Rep a),
289-
A.GToEncoding A.Zero (Rep a),
290-
A.GToJSONKey (Rep a)
291-
) =>
292-
ToJSONKey (GenericType a)
293-
where
294-
toJSONKey = contramap unGenericType $ A.genericToJSONKey A.defaultJSONKeyOptions
295-
296-
instance
297-
( Generic a,
298-
Typeable a,
299-
Binary.GBinaryPut (Rep a),
300-
Binary.GBinaryGet (Rep a)
301-
) =>
302-
Binary (GenericType a)
303-
where
304-
putList = defaultPutList
305-
put = Binary.gput . Generics.from . unGenericType
306-
get = GenericType . Generics.to <$> Binary.gget
307-
308-
{-# INLINE defaultPutList #-}
309-
defaultPutList :: (Binary a) => [a] -> Binary.Put
310-
defaultPutList xs = Binary.put (length xs) <> mapM_ Binary.put xs
311-
312-
optsAeson :: forall a. (Typeable a) => A.Options
313-
optsAeson =
314-
A.defaultOptions
315-
{ A.fieldLabelModifier = \case
316-
raw@('_' : inp) ->
317-
case fmt inp of
318-
out | out == inp -> fmt raw
319-
out -> out
320-
raw ->
321-
fmt raw,
322-
A.constructorTagModifier = id,
323-
A.allNullaryToStringTag = True,
324-
A.omitNothingFields = True,
325-
A.sumEncoding = A.defaultTaggedObject,
326-
A.unwrapUnaryRecords = False,
327-
A.tagSingleConstructors = False
328-
}
329-
where
330-
fmt = Toml.stripTypeNamePrefix $ Proxy @a

0 commit comments

Comments
 (0)