@@ -37,35 +37,64 @@ pub async fn generate_enum(
37
37
let name: String = pascal_case ( & en. name ) ;
38
38
39
39
// Some enums are shared between all schemas
40
+ // Hasura suffixes 'Enum' to the end of custom enums created
41
+ // via a table with 'value' and 'comment' columns.
40
42
if global_enum_suffixes
41
43
. iter ( )
42
44
. any ( |suffix| name. ends_with ( suffix) )
43
45
{
44
- let e = Enum :: new ( & name) . with_values ( & values) . to_string ( ) ;
45
-
46
- let instances = enum_instances ( & name, & values, & original_values) ;
47
- let package_name = pascal_case ( & workspace_config. shared_graphql_enums_lib ) ;
48
- let module_name = format ! ( "{package_name}.{name}" ) ;
49
- imports. push ( PurescriptImport :: new ( & module_name, "oa-gql-enums" ) . add_specified ( & name) ) ;
50
-
51
- let lib_path = format ! (
52
- "{}{}" ,
53
- & workspace_config. shared_graphql_enums_dir, & workspace_config. shared_graphql_enums_lib
54
- ) ;
55
- write (
56
- & format ! ( "{lib_path}/src/{package_name}/{name}.purs" ) ,
57
- & format ! (
58
- "module {module_name} ({name}(..)) where\n \n {MODULE_IMPORTS}\n \n {e}{instances}"
59
- ) ,
60
- ) ;
61
- write ( & format ! ( "{lib_path}/spago.yaml" ) , & enums_spago_yaml ( ) ) ;
62
- None
46
+ if use_variant ( & name, & workspace_config) {
47
+ let lib_path = format ! (
48
+ "{}{}" ,
49
+ & workspace_config. shared_graphql_enums_dir,
50
+ & workspace_config. shared_graphql_enums_lib
51
+ ) ;
52
+ let package_name = pascal_case ( & workspace_config. shared_graphql_enums_lib ) ;
53
+
54
+ if let Some ( variant) = variant_mod ( & name, & original_values) {
55
+ write (
56
+ & format ! ( "{lib_path}/src/{package_name}/{name}.purs" ) ,
57
+ & variant,
58
+ ) ;
59
+ write ( & format ! ( "{lib_path}/spago.yaml" ) , & enums_spago_yaml ( ) ) ;
60
+ }
61
+
62
+ None
63
+ } else {
64
+ let e = Enum :: new ( & name) . with_values ( & values) . to_string ( ) ;
65
+
66
+ let instances = enum_instances ( & name, & values, & original_values) ;
67
+ let package_name = pascal_case ( & workspace_config. shared_graphql_enums_lib ) ;
68
+ let module_name = format ! ( "{package_name}.{name}" ) ;
69
+ imports. push ( PurescriptImport :: new ( & module_name, "oa-gql-enums" ) . add_specified ( & name) ) ;
70
+
71
+ let lib_path = format ! (
72
+ "{}{}" ,
73
+ & workspace_config. shared_graphql_enums_dir,
74
+ & workspace_config. shared_graphql_enums_lib
75
+ ) ;
76
+ write (
77
+ & format ! ( "{lib_path}/src/{package_name}/{name}.purs" ) ,
78
+ & format ! (
79
+ "module {module_name} ({name}(..)) where\n \n {MODULE_IMPORTS}\n \n {e}{instances}"
80
+ ) ,
81
+ ) ;
82
+ write ( & format ! ( "{lib_path}/spago.yaml" ) , & enums_spago_yaml ( ) ) ;
83
+ None
84
+ }
63
85
// Otherwise write schema-specific variant enums
64
86
} else {
65
87
Some ( Variant :: new ( & name) . with_values ( & original_values) )
66
88
}
67
89
}
68
90
91
+ fn use_variant ( name : & str , workspace_config : & WorkspaceConfig ) -> bool {
92
+ workspace_config
93
+ . variant_enums
94
+ . iter ( )
95
+ . any ( |suffix| name. ends_with ( suffix) )
96
+ }
97
+
69
98
fn first_upper ( s : & str ) -> String {
70
99
let mut c = s. chars ( ) ;
71
100
match c. next ( ) {
@@ -185,6 +214,173 @@ fn enum_instances(name: &str, values: &Vec<String>, original_values: &Vec<String
185
214
instances
186
215
}
187
216
217
+ fn variant_mod ( name : & str , original_values : & Vec < String > ) -> Option < String > {
218
+ if original_values. len ( ) == 0 {
219
+ return None ;
220
+ }
221
+
222
+ let values: Vec < String > = original_values. iter ( ) . map ( |v| v. to_lowercase ( ) ) . collect ( ) ;
223
+
224
+ let mut instances = String :: new ( ) ;
225
+ let first_value = & values[ 0 ] ;
226
+ let last_value = values
227
+ . last ( )
228
+ . expect ( "Enums should have at least one value in order to get last." ) ;
229
+
230
+ let mut variant = String :: new ( ) ;
231
+ let mut variant_fns = String :: new ( ) ;
232
+
233
+ // Define the type
234
+ variant. push_str ( & format ! (
235
+ r#"
236
+ type {name} = Variant"#
237
+ ) ) ;
238
+
239
+ for value in & values {
240
+ let variant_name = value. to_lowercase ( ) ;
241
+ let variant_member = if value == first_value {
242
+ format ! ( " ( {variant_name}\n " )
243
+ } else {
244
+ format ! ( " , {variant_name}\n " )
245
+ } ;
246
+
247
+ // Add the variant member to the row
248
+ variant. push_str ( & variant_member) ;
249
+
250
+ // Define the variant fn for easy calling
251
+ variant_fns. push_str ( & to_variant ( name, & variant_name) ) ;
252
+ }
253
+
254
+ // Add the variant type closing bracket
255
+ variant. push_str ( "\n )" ) ;
256
+
257
+ // instances:
258
+
259
+ // Next values in the enum
260
+ let succ_values = values
261
+ . iter ( )
262
+ . enumerate ( )
263
+ . map ( |( i, v) | {
264
+ if i == values. len ( ) - 1 {
265
+ format ! ( "{} -> Nothing" , v)
266
+ } else {
267
+ format ! ( "{} -> Just {}" , v, values[ i + 1 ] )
268
+ }
269
+ } )
270
+ . collect :: < Vec < String > > ( )
271
+ . join ( "\n " ) ;
272
+
273
+ // Previous values in the enum
274
+ let pred_values = values
275
+ . iter ( )
276
+ . enumerate ( )
277
+ . map ( |( i, v) | {
278
+ if i == 0 {
279
+ format ! ( "{} -> Nothing" , v)
280
+ } else {
281
+ format ! ( "{} -> Just {}" , v, values[ i - 1 ] )
282
+ }
283
+ } )
284
+ . collect :: < Vec < String > > ( )
285
+ . join ( "\n " ) ;
286
+
287
+ // Cardinality of the enum
288
+ let cardinality = values. len ( ) ;
289
+
290
+ // Convert an enum index to the corresponding value
291
+ let to_enum = values
292
+ . iter ( )
293
+ . enumerate ( )
294
+ . map ( |( i, v) | format ! ( "{} -> Just {}" , i, v) )
295
+ . collect :: < Vec < String > > ( )
296
+ . join ( "\n " ) ;
297
+
298
+ // Convert an enum value to the corresponding index
299
+ let from_enum = values
300
+ . iter ( )
301
+ . enumerate ( )
302
+ . map ( |( i, v) | format ! ( "{} -> {}" , v, i) )
303
+ . collect :: < Vec < String > > ( )
304
+ . join ( "\n " ) ;
305
+
306
+ let decode_json = values
307
+ . iter ( )
308
+ . zip ( original_values. iter ( ) )
309
+ . map ( |( v, original) | format ! ( r#""{original}" -> pure {v}"# ) )
310
+ . collect :: < Vec < String > > ( )
311
+ . join ( "\n " ) ;
312
+
313
+ let encode_json = values
314
+ . iter ( )
315
+ . zip ( original_values. iter ( ) )
316
+ . map ( |( v, original) | format ! ( r#"on (Proxy @"{v}") (\_ -> show {original})"# ) )
317
+ . collect :: < Vec < String > > ( )
318
+ . join ( "\n " ) ;
319
+
320
+ instances. push_str ( & format ! (
321
+ r#"
322
+
323
+ instance DecodeJson {name} where
324
+ decodeJson = decodeJson >=> case _ of
325
+ {decode_json}
326
+ s -> Left $ TypeMismatch $ \"Not a {name}: \" <> s
327
+
328
+ instance EncodeJson {name} where
329
+ encodeJson = case_
330
+ {encode_json}
331
+
332
+ instance MakeFixture {name} where mkFixture = {first_value}
333
+
334
+ instance Show {name} where
335
+ show a = unvariant q.data_type # \(Unvariant f) -> f \p _ -> reflectSymbol p
336
+
337
+ instance Eq {name} where
338
+ eq = eq `on` show
339
+
340
+ instance Ord {name} where
341
+ compare = compare `on` show
342
+
343
+ instance GqlArgString {name} where
344
+ toGqlArgStringImpl = show
345
+
346
+ instance DecodeHasura {name} where
347
+ decodeHasura = decodeJson
348
+
349
+ instance EncodeHasura {name} where
350
+ encodeHasura = encodeJson
351
+
352
+ instance Enum {name} where
353
+ succ a = case a of
354
+ {succ_values}
355
+ pred a = case a of
356
+ {pred_values}
357
+
358
+ instance Bounded {name} where
359
+ top = {last_value}
360
+ bottom = {first_value}
361
+
362
+ instance BoundedEnum {name} where
363
+ cardinality = Cardinality {cardinality}
364
+ toEnum a = case a of
365
+ {to_enum}
366
+ _ -> Nothing
367
+ fromEnum a = case a of
368
+ {from_enum}
369
+ "#
370
+ ) ) ;
371
+
372
+ Some ( format ! ( "module {name} where\n \n {VARIANT_MODULE_IMPORTS}\n \n {variant}\n \n {variant_fns}\n \n {instances}" ) )
373
+ }
374
+
375
+ fn to_variant ( type_name : & str , name : & str ) -> String {
376
+ format ! (
377
+ r#"
378
+ var :: {type_name}
379
+ var = inj (Proxy @"{name}") unit
380
+ "#
381
+ )
382
+ }
383
+
188
384
fn enums_spago_yaml ( ) -> String {
189
385
r#"package:
190
386
name: oa-gql-enums
@@ -201,6 +397,7 @@ fn enums_spago_yaml() -> String {
201
397
- prelude
202
398
- simple-json
203
399
- transformers
400
+ - variant
204
401
- oa-make-fixture
205
402
- oa-encode-decode
206
403
"#
@@ -227,3 +424,9 @@ import Data.Bifunctor (lmap)
227
424
import Foreign.Class as FC
228
425
import Class.EncodeOa (class EncodeOa)
229
426
import Class.DecodeOa (class DecodeOa)"# ;
427
+
428
+ const VARIANT_MODULE_IMPORTS : & str = r#"import Prelude
429
+
430
+ import Data.Variant (Unvariant(..), Variant, inj, unvariant)
431
+ import Data.Enum (class Enum, class BoundedEnum, Cardinality(..))
432
+ import Proxy (Proxy(..))"# ;
0 commit comments