Skip to content

Commit ec6c898

Browse files
committed
functora-uri package wip
1 parent d22c70a commit ec6c898

File tree

5 files changed

+139
-3
lines changed

5 files changed

+139
-3
lines changed

pub/functora/functora.cabal

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,17 @@ common pkg-aes
158158
, Crypto
159159
, pkcs7
160160

161+
common pkg-uri
162+
import: pkg
163+
hs-source-dirs: src/uri
164+
build-depends:
165+
, base
166+
, modern-uri
167+
, tomland
168+
169+
if ((impl(ghcjs) || arch(javascript)) || os(wasi))
170+
build-depends: jsaddle
171+
161172
common pkg-cfg
162173
import: pkg
163174
hs-source-dirs: src/cfg
@@ -298,6 +309,15 @@ library aes
298309
Functora.Aes
299310
Functora.AesOrphan
300311

312+
library uri
313+
import: pkg-uri
314+
build-depends: functora
315+
exposed: True
316+
visibility: public
317+
exposed-modules:
318+
Functora.Uri
319+
Functora.Uri.ToQuery
320+
301321
library cfg
302322
import: pkg-cfg
303323
build-depends: functora
@@ -410,14 +430,16 @@ test-suite functora-test
410430
Functora.Tags.TestFgpt
411431
Functora.Tags.TestSing
412432
Functora.TagsSpec
433+
Functora.UriSpec
413434
Functora.WebSpec
414435

415436
if flag(ghcid)
416437
import:
417438
pkg-prelude, pkg-qr, pkg-aes,
418439
pkg-cfg, pkg-web, pkg-sql,
419440
pkg-money, pkg-rates, pkg-tags,
420-
pkg-soplate, pkg-elm2miso, pkg-bolt11
441+
pkg-soplate, pkg-elm2miso, pkg-bolt11,
442+
pkg-uri
421443

422444
ghc-options: -Wno-unused-packages
423445
other-modules:
@@ -442,6 +464,8 @@ test-suite functora-test
442464
Functora.TagsFamily
443465
Functora.TagsOrphan
444466
Functora.Unicode
467+
Functora.Uri
468+
Functora.Uri.ToQuery
445469
Functora.Web
446470
Functora.WebOrphan
447471

@@ -457,4 +481,5 @@ test-suite functora-test
457481
, rates
458482
, soplate
459483
, tags
484+
, uri
460485
, web

pub/functora/src/functora-ghcjs.cabal

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ common pkg
167167

168168
library
169169
import: pkg
170-
hs-source-dirs: prelude qr aes money web rates tags cfg
170+
hs-source-dirs: prelude qr aes money web rates tags cfg uri
171171

172172
if !os(wasi)
173173
hs-source-dirs: bolt11
@@ -188,6 +188,8 @@ library
188188
Functora.Rfc2397
189189
Functora.Tags
190190
Functora.Unicode
191+
Functora.Uri
192+
Functora.Uri.ToQuery
191193
Functora.Web
192194
Functora.WebOrphan
193195

@@ -200,7 +202,7 @@ test-suite functora-ghcjs-test
200202
type: exitcode-stdio-1.0
201203
main-is: Spec.hs
202204
cpp-options: -DNOSOP
203-
hs-source-dirs: prelude qr aes money web rates tags cfg elm2miso test
205+
hs-source-dirs: prelude qr aes money web rates tags cfg elm2miso test uri
204206

205207
if !os(wasi)
206208
hs-source-dirs: bolt11
@@ -234,6 +236,7 @@ test-suite functora-ghcjs-test
234236
Functora.Tags.TestFgpt
235237
Functora.Tags.TestSing
236238
Functora.TagsSpec
239+
Functora.UriSpec
237240
Functora.WebSpec
238241

239242
other-modules:
@@ -254,5 +257,7 @@ test-suite functora-ghcjs-test
254257
Functora.TagsFamily
255258
Functora.TagsOrphan
256259
Functora.Unicode
260+
Functora.Uri
261+
Functora.Uri.ToQuery
257262
Functora.Web
258263
Functora.WebOrphan
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module Functora.UriSpec (spec) where
2+
3+
import Functora.Prelude
4+
import Functora.Uri
5+
import Test.Hspec
6+
import Text.URI
7+
8+
data Foo = Foo
9+
{ fooBar :: Int,
10+
fooBuz :: Text,
11+
fooBuf :: String
12+
}
13+
deriving stock (Eq, Ord, Show, Data, Generic)
14+
15+
instance ToQuery Foo
16+
17+
mkSample :: (MonadThrow m) => m (Foo, [QueryParam])
18+
mkSample = do
19+
let bar = 123 :: Int
20+
let buz = "example" :: Text
21+
let buf = "Hello, World!" :: String
22+
kBar <- mkQueryKey "bar"
23+
vBar <- mkQueryValue $ inspect bar
24+
kBuz <- mkQueryKey "buz"
25+
vBuz <- mkQueryValue buz
26+
kBuf <- mkQueryKey "buf"
27+
vBuf <- mkQueryValue $ from @String @Text buf
28+
pure
29+
( Foo bar buz buf,
30+
[ QueryParam kBar vBar,
31+
QueryParam kBuz vBuz,
32+
QueryParam kBuf vBuf
33+
]
34+
)
35+
36+
spec :: Spec
37+
spec = do
38+
focus . it "ToQuery" $ do
39+
sample <- mkSample
40+
toQuery (fst sample) `shouldBe` snd sample
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Functora.Uri (module X) where
2+
3+
import Functora.Uri.ToQuery as X
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE UndecidableInstances #-}
3+
4+
module Functora.Uri.ToQuery (ToQuery (..)) where
5+
6+
import Functora.Prelude
7+
import GHC.Generics hiding (from)
8+
import qualified GHC.Generics as G
9+
import Text.URI
10+
import qualified Toml
11+
#if defined(__GHCJS__) && defined(ghcjs_HOST_OS) && defined(wasi_HOST_OS)
12+
import Data.JSString (JSString)
13+
#endif
14+
15+
class (Typeable a) => ToQuery a where
16+
toQuery :: a -> [QueryParam]
17+
default toQuery :: (Generic a, GToQuery (Rep a)) => a -> [QueryParam]
18+
toQuery = gToQuery (Toml.stripTypeNamePrefix $ Proxy @a) . G.from
19+
20+
class GToQuery f where
21+
gToQuery :: (String -> String) -> f p -> [QueryParam]
22+
23+
-- Handle datatype metadata
24+
instance (GToQuery a) => GToQuery (M1 D c a) where
25+
gToQuery fmt (M1 x) = gToQuery fmt x
26+
27+
-- Handle constructor metadata
28+
instance (GToQuery a) => GToQuery (M1 C c a) where
29+
gToQuery fmt (M1 x) = gToQuery fmt x
30+
31+
instance (Selector s, ToQueryField a) => GToQuery (M1 S s (K1 i a)) where
32+
gToQuery fmt m1@(M1 (K1 a)) = do
33+
let name = selName m1
34+
if null name
35+
then mempty -- Skip if there is no field name (like unnamed tuples)
36+
else do
37+
k <- mkQueryKey . pack $ fmt name
38+
v <- mkQueryValue $ toQueryField a
39+
pure $ QueryParam k v
40+
41+
-- Handle product type
42+
instance (GToQuery a, GToQuery b) => GToQuery (a :*: b) where
43+
gToQuery fmt (a :*: b) = gToQuery fmt a ++ gToQuery fmt b
44+
45+
class ToQueryField a where
46+
toQueryField :: a -> Text
47+
48+
instance ToQueryField Text where
49+
toQueryField = id
50+
51+
instance ToQueryField String where
52+
toQueryField = from @String @Text
53+
54+
instance ToQueryField Int where
55+
toQueryField = inspect
56+
57+
instance ToQueryField Integer where
58+
toQueryField = inspect
59+
60+
#if defined(__GHCJS__) && defined(ghcjs_HOST_OS) && defined(wasi_HOST_OS)
61+
instance ToQueryField JSString where
62+
toQueryField = from @JSString @Text
63+
#endif

0 commit comments

Comments
 (0)