0 | ||| Parse and convert URL pieces and headers.
  1 | module Pact.API.HttpApiData
  2 |
  3 | import Data.String
  4 | import Data.Vect
  5 | import Data.List1
  6 |
  7 | ||| Parse a URL piece or header into a value.
  8 | public export
  9 | interface FromHttpApiData a where
 10 |   ||| Parse a URL piece into a value.
 11 |   parseUrlPiece : String -> Either String a
 12 |
 13 |   ||| Parse a header into a value.
 14 |   parseHeader : String -> Either String a
 15 |   parseHeader = parseUrlPiece
 16 |
 17 |   ||| Parse a query parameter into a value.
 18 |   parseQueryParam : String -> Either String a
 19 |   parseQueryParam = parseUrlPiece
 20 |
 21 | public export
 22 | implementation FromHttpApiData () where
 23 |   parseUrlPiece _ = Right ()
 24 |
 25 | public export
 26 | implementation FromHttpApiData Bool where
 27 |   parseUrlPiece s = case s of
 28 |     "true" => Right True
 29 |     "false" => Right False
 30 |     _ => Left "Invalid Bool"
 31 |
 32 | public export
 33 | implementation FromHttpApiData Char where
 34 |   parseUrlPiece s = case asList s of
 35 |     [c] => Right c
 36 |     _ => Left "Invalid Char"
 37 |
 38 | public export
 39 | implementation FromHttpApiData String where
 40 |   parseUrlPiece = Right
 41 |
 42 |
 43 | public export
 44 | implementation FromHttpApiData Nat where
 45 |   parseUrlPiece s = case parsePositive s of
 46 |     Just n => Right n
 47 |     Nothing => Left "Invalid Int"
 48 |
 49 | public export
 50 | implementation FromHttpApiData Int where
 51 |   parseUrlPiece s = case parseInteger s of
 52 |     Just n => Right n
 53 |     Nothing => Left "Invalid Int"
 54 |
 55 | public export
 56 | implementation FromHttpApiData Integer where
 57 |   parseUrlPiece s = case parseInteger s of
 58 |     Just n => Right n
 59 |     Nothing => Left "Invalid Integer"
 60 |
 61 | public export
 62 | implementation FromHttpApiData Int8 where
 63 |   parseUrlPiece s = case parseInteger { a = Int8 } s of
 64 |     Just n => if n > 127 || n < -128 then Left "Invalid Int8" else Right n
 65 |     Nothing => Left "Invalid Int8"
 66 |
 67 | public export
 68 | implementation FromHttpApiData Int16 where
 69 |   parseUrlPiece s = case parseInteger { a = Int16 } s of
 70 |     Just n => if n > 32767 || n < -32768 then Left "Invalid Int16" else Right n
 71 |     Nothing => Left "Invalid Int16"
 72 |
 73 | public export
 74 | implementation FromHttpApiData Int32 where
 75 |   parseUrlPiece s = case parseInteger { a = Int32 } s of
 76 |     Just n => if n > 2147483647 || n < -2147483648 then Left "Invalid Int32" else Right n
 77 |     Nothing => Left "Invalid Int32"
 78 |
 79 | public export
 80 | implementation FromHttpApiData Int64 where
 81 |   parseUrlPiece s = case parseInteger { a = Int64 } s of
 82 |     Just n => if n > 9223372036854775807 || n < -9223372036854775808 then Left "Invalid Int64" else Right n
 83 |     Nothing => Left "Invalid Int64"
 84 |
 85 | public export
 86 | implementation FromHttpApiData Bits8 where
 87 |   parseUrlPiece s = case parsePositive { a = Bits8 } s of
 88 |     Just n => if n > 255 then Left "Invalid Bits8" else Right n
 89 |     Nothing => Left "Invalid Bits8"
 90 |
 91 | public export
 92 | implementation FromHttpApiData Bits16 where
 93 |   parseUrlPiece s = case parsePositive { a = Bits16 } s of
 94 |     Just n => if n > 65535 then Left "Invalid Bits16" else Right n
 95 |     Nothing => Left "Invalid Bits16"
 96 |
 97 | public export
 98 | implementation FromHttpApiData Bits32 where
 99 |   parseUrlPiece s = case parsePositive { a = Bits32 } s of
100 |     Just n => if n > 4294967295 then Left "Invalid Bits32" else Right n
101 |     Nothing => Left "Invalid Bits32"
102 |
103 | public export
104 | implementation FromHttpApiData Bits64 where
105 |   parseUrlPiece s = case parsePositive { a = Bits64 } s of
106 |     Just n => if n > 18446744073709551615 then Left "Invalid Bits64" else Right n
107 |     Nothing => Left "Invalid Bits64"
108 |
109 | public export
110 | implementation FromHttpApiData Double where
111 |   parseUrlPiece s = case parseDouble s of
112 |     Just n => Right n
113 |     Nothing => Left "Invalid Double"
114 |
115 | public export
116 | implementation FromHttpApiData a => FromHttpApiData (Maybe a) where
117 |   parseUrlPiece s = case s of
118 |     "" => Right Nothing
119 |     _ => map Just $ parseUrlPiece s
120 |
121 | public export
122 | implementation Monoid a => FromHttpApiData b => FromHttpApiData (Either a b) where
123 |   parseUrlPiece s = case s of
124 |     "" => Right $ Left neutral
125 |     _ => map Right $ parseUrlPiece s
126 |
127 |
128 | public export
129 | implementation FromHttpApiData a => FromHttpApiData (List1 a) where
130 |   parseUrlPiece s = case s of
131 |     "" => Left "Invalid List1"
132 |     _ => Data.String.split (== ',') s |> map parseUrlPiece |> sequence
133 |
134 | public export
135 | implementation FromHttpApiData a => FromHttpApiData (List a) where
136 |   parseUrlPiece s = case s of
137 |     "" => Right []
138 |     _ => map forget $ parseUrlPiece s
139 |
140 | public export
141 | implementation FromHttpApiData a => FromHttpApiData (n ** Vect n awhere
142 |   parseUrlPiece s = case s of
143 |     "" => Right (0 ** [])
144 |     _ => parseUrlPiece {a = List a} s |> map (\list => (length list ** fromList list))
145 |
146 |
147 | ||| Convert a value to a URL piece or header.
148 | public export
149 | interface ToHttpApiData a where
150 |   ||| Convert a value to a URL piece.
151 |   toUrlPiece : a -> String
152 |
153 |   ||| Convert a value to a header.
154 |   toHeader : a -> String
155 |   toHeader = toUrlPiece
156 |
157 |   ||| Convert a value to a query parameter.
158 |   toQueryParam : a -> String
159 |   toQueryParam = toUrlPiece
160 |
161 | public export
162 | implementation ToHttpApiData String where
163 |   toUrlPiece = id
164 |
165 | public export 
166 | implementation ToHttpApiData () where
167 |   toUrlPiece () = ""
168 |
169 | public export
170 | implementation ToHttpApiData Bool where
171 |   toUrlPiece b = if b then "true" else "false"
172 |
173 | public export
174 | implementation ToHttpApiData Char where
175 |   toUrlPiece c = singleton c
176 |
177 | public export
178 | implementation ToHttpApiData Nat where
179 |   toUrlPiece = show
180 |
181 | public export
182 | implementation ToHttpApiData Int where
183 |   toUrlPiece = show
184 |
185 | public export
186 | implementation ToHttpApiData Integer where
187 |   toUrlPiece = show
188 |
189 | public export
190 | implementation ToHttpApiData Int8 where
191 |   toUrlPiece = show
192 |
193 | public export
194 | implementation ToHttpApiData Int16 where
195 |   toUrlPiece = show
196 |
197 | public export
198 | implementation ToHttpApiData Int32 where
199 |   toUrlPiece = show
200 |
201 | public export
202 | implementation ToHttpApiData Int64 where
203 |   toUrlPiece = show
204 |
205 | public export
206 | implementation ToHttpApiData Bits8 where
207 |   toUrlPiece = show
208 |
209 | public export
210 | implementation ToHttpApiData Bits16 where
211 |   toUrlPiece = show
212 |
213 | public export
214 | implementation ToHttpApiData Bits32 where
215 |   toUrlPiece = show
216 |
217 | public export
218 | implementation ToHttpApiData Bits64 where
219 |   toUrlPiece = show
220 |
221 | public export
222 | implementation ToHttpApiData Double where
223 |   toUrlPiece = show
224 |
225 | public export
226 | implementation ToHttpApiData a => ToHttpApiData (Maybe a) where
227 |   toUrlPiece = maybe "" toUrlPiece
228 |
229 | public export
230 | implementation ToHttpApiData a => ToHttpApiData (Either a b) where
231 |   toUrlPiece = either toUrlPiece $ const ""
232 |
233 | public export
234 | implementation ToHttpApiData a => ToHttpApiData (List a) where
235 |   toUrlPiece = joinBy "," . map toUrlPiece
236 |
237 | public export
238 | implementation ToHttpApiData a => ToHttpApiData (List1 a) where
239 |   toUrlPiece = joinBy "," . toList . map toUrlPiece
240 |
241 | public export
242 | implementation ToHttpApiData a => ToHttpApiData (n ** Vect n awhere
243 |   toUrlPiece (n ** v= joinBy "," . toList $ map toUrlPiece v
244 |