@@ -0,0 +1,652 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE QuasiQuotes #-}
5+module Data.Swagger.CommonTestTypes where
10+ import Data.Aeson (Value, ToJSON(..), ToJSONKey(..))
11+ import Data.Aeson.Types (toJSONKeyText)
15+ import Data.Set (Set)
16+ import Data.Map (Map)
17+ import qualified Data.Text as Text
21+ import Data.Swagger.Declare
22+ import Data.Swagger.Internal (SwaggerKind(..))
24+ -- ========================================================================
26+ -- ========================================================================
28+ data Unit = Unit deriving (Generic)
29+ instance ToParamSchema Unit
30+ instance ToSchema Unit
32+ unitSchemaJSON :: Value
33+ unitSchemaJSON = [aesonQQ|
40+ -- ========================================================================
42+ -- ========================================================================
48+ instance ToParamSchema Color
49+ instance ToSchema Color
51+ colorSchemaJSON :: Value
52+ colorSchemaJSON = [aesonQQ|
55+ "enum": ["Red", "Green", "Blue"]
59+ -- ========================================================================
60+ -- Shade (paramSchemaToNamedSchema)
61+ -- ========================================================================
63+ data Shade = Dim | Bright deriving (Generic)
64+ instance ToParamSchema Shade
66+ instance ToSchema Shade where declareNamedSchema = pure . paramSchemaToNamedSchema defaultSchemaOptions
68+ shadeSchemaJSON :: Value
69+ shadeSchemaJSON = [aesonQQ|
72+ "enum": ["Dim", "Bright"]
76+ -- ========================================================================
77+ -- Paint (record with bounded enum property)
78+ -- ========================================================================
80+ newtype Paint = Paint { color :: Color }
82+ instance ToSchema Paint
84+ paintSchemaJSON :: Value
85+ paintSchemaJSON = [aesonQQ|
92+ "$ref": "#/definitions/Color"
95+ "required": ["color"]
99+ paintInlinedSchemaJSON :: Value
100+ paintInlinedSchemaJSON = [aesonQQ|
108+ "enum": ["Red", "Green", "Blue"]
111+ "required": ["color"]
115+ -- ========================================================================
116+ -- Status (constructorTagModifier)
117+ -- ========================================================================
124+ instance ToParamSchema Status where
125+ toParamSchema = genericToParamSchema defaultSchemaOptions
126+ { constructorTagModifier = map toLower . drop (length "Status") }
127+ instance ToSchema Status where
128+ declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
129+ { constructorTagModifier = map toLower . drop (length "Status") }
131+ statusSchemaJSON :: Value
132+ statusSchemaJSON = [aesonQQ|
135+ "enum": ["ok", "error"]
139+ -- ========================================================================
140+ -- Email (newtype with unwrapUnaryRecords set to True)
141+ -- ========================================================================
143+ newtype Email = Email { getEmail :: String }
145+ instance ToParamSchema Email
146+ instance ToSchema Email where
147+ declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
148+ { unwrapUnaryRecords = True }
150+ emailSchemaJSON :: Value
151+ emailSchemaJSON = [aesonQQ|
157+ -- ========================================================================
158+ -- UserId (non-record newtype)
159+ -- ========================================================================
161+ newtype UserId = UserId Integer
162+ deriving (Eq, Ord, Generic)
163+ instance ToParamSchema UserId
164+ instance ToSchema UserId
166+ userIdSchemaJSON :: Value
167+ userIdSchemaJSON = [aesonQQ|
173+ -- ========================================================================
174+ -- UserGroup (set newtype)
175+ -- ========================================================================
177+ newtype UserGroup = UserGroup (Set UserId)
179+ instance ToSchema UserGroup
181+ userGroupSchemaJSON :: Value
182+ userGroupSchemaJSON = [aesonQQ|
185+ "items": { "$ref": "#/definitions/UserId" },
190+ -- ========================================================================
191+ -- Person (simple record with optional fields)
192+ -- ========================================================================
193+ data Person = Person
196+ , email :: Maybe String
197+ } deriving (Generic)
199+ instance ToSchema Person
201+ personSchemaJSON :: Value
202+ personSchemaJSON = [aesonQQ|
207+ "name": { "type": "string" },
208+ "phone": { "type": "integer" },
209+ "email": { "type": "string" }
211+ "required": ["name", "phone"]
215+ -- ========================================================================
216+ -- Player (record newtype)
217+ -- ========================================================================
219+ newtype Player = Player
221+ } deriving (Generic)
222+ instance ToSchema Player
224+ playerSchemaJSON :: Value
225+ playerSchemaJSON = [aesonQQ|
232+ "$ref": "#/definitions/Point"
235+ "required": ["position"]
239+ newtype Players = Players [Inlined Player]
241+ instance ToSchema Players
243+ playersSchemaJSON :: Value
244+ playersSchemaJSON = [aesonQQ|
254+ "$ref": "#/definitions/Point"
257+ "required": ["position"]
262+ -- ========================================================================
263+ -- Character (sum type with ref and record in alternative)
264+ -- ========================================================================
268+ | NPC { npcName :: String, npcPosition :: Point }
270+ instance ToSchema Character
272+ characterSchemaJSON :: Value
273+ characterSchemaJSON = [aesonQQ|
278+ "PC": { "$ref": "#/definitions/Player" },
284+ "npcName": { "type": "string" },
285+ "npcPosition": { "$ref": "#/definitions/Point" }
287+ "required": ["npcName", "npcPosition"]
295+ characterInlinedSchemaJSON :: Value
296+ characterInlinedSchemaJSON = [aesonQQ|
311+ "x": { "type": "number", "format": "double" },
312+ "y": { "type": "number", "format": "double" }
314+ "required": ["x", "y"]
317+ "required": ["position"]
324+ "npcName": { "type": "string" },
330+ "x": { "type": "number", "format": "double" },
331+ "y": { "type": "number", "format": "double" }
333+ "required": ["x", "y"]
336+ "required": ["npcName", "npcPosition"]
344+ characterInlinedPlayerSchemaJSON :: Value
345+ characterInlinedPlayerSchemaJSON = [aesonQQ|
357+ "$ref": "#/definitions/Point"
360+ "required": ["position"]
367+ "npcName": { "type": "string" },
368+ "npcPosition": { "$ref": "#/definitions/Point" }
370+ "required": ["npcName", "npcPosition"]
378+ -- ========================================================================
379+ -- ISPair (non-record product data type)
380+ -- ========================================================================
381+ data ISPair = ISPair Integer String
384+ instance ToSchema ISPair
386+ ispairSchemaJSON :: Value
387+ ispairSchemaJSON = [aesonQQ|
392+ { "type": "integer" },
393+ { "type": "string" }
400+ -- ========================================================================
401+ -- Point (record data type with custom fieldLabelModifier)
402+ -- ========================================================================
407+ } deriving (Generic)
409+ instance ToSchema Point where
410+ declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
411+ { fieldLabelModifier = map toLower . drop (length "point") }
413+ pointSchemaJSON :: Value
414+ pointSchemaJSON = [aesonQQ|
419+ "x": { "type": "number", "format": "double" },
420+ "y": { "type": "number", "format": "double" }
422+ "required": ["x", "y"]
426+ -- ========================================================================
427+ -- Point (record data type with multiple fields)
428+ -- ========================================================================
430+ data Point5 = Point5
435+ , point5V :: Double -- 5 dimensional!
436+ } deriving (Generic)
438+ instance ToSchema Point5 where
439+ declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
440+ { fieldLabelModifier = map toLower . drop (length "point5") }
442+ point5SchemaJSON :: Value
443+ point5SchemaJSON = [aesonQQ|
448+ "x": { "type": "number", "format": "double" },
449+ "y": { "type": "number", "format": "double" },
450+ "z": { "type": "number", "format": "double" },
451+ "u": { "type": "number", "format": "double" },
452+ "v": { "type": "number", "format": "double" }
454+ "required": ["x", "y", "z", "u", "v"]
458+ point5Properties :: [String]
459+ point5Properties = ["x", "y", "z", "u", "v"]
461+ -- ========================================================================
462+ -- MyRoseTree (custom datatypeNameModifier)
463+ -- ========================================================================
465+ data MyRoseTree = MyRoseTree
467+ , trees :: [MyRoseTree]
468+ } deriving (Generic)
470+ instance ToSchema MyRoseTree where
471+ declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
472+ { datatypeNameModifier = drop (length "My") }
474+ myRoseTreeSchemaJSON :: Value
475+ myRoseTreeSchemaJSON = [aesonQQ|
480+ "root": { "type": "string" },
486+ "$ref": "#/definitions/RoseTree"
490+ "required": ["root", "trees"]
494+ data MyRoseTree' = MyRoseTree'
496+ , trees' :: [MyRoseTree']
497+ } deriving (Generic)
499+ instance ToSchema MyRoseTree' where
500+ declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
501+ { datatypeNameModifier = map toLower }
503+ myRoseTreeSchemaJSON' :: Value
504+ myRoseTreeSchemaJSON' = [aesonQQ|
509+ "root'": { "type": "string" },
515+ "$ref": "#/definitions/myrosetree'"
519+ "required": ["root'", "trees'"]
523+ -- ========================================================================
524+ -- Inlined (newtype for inlining schemas)
525+ -- ========================================================================
527+ newtype Inlined a = Inlined { getInlined :: a }
529+ instance ToSchema a => ToSchema (Inlined a) where
530+ declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
532+ unname (NamedSchema _ s) = NamedSchema Nothing s
534+ -- ========================================================================
535+ -- Light (sum type with unwrapUnaryRecords)
536+ -- ========================================================================
542+ | LightWaveLength { waveLength :: Double }
545+ instance ToSchema Light where
546+ declareNamedSchema = genericDeclareNamedSchemaUnrestricted defaultSchemaOptions
547+ { unwrapUnaryRecords = True }
549+ lightSchemaJSON :: Value
550+ lightSchemaJSON = [aesonQQ|
555+ "NoLight": { "type": "array", "items": [] },
556+ "LightFreq": { "type": "number", "format": "double" },
557+ "LightColor": { "$ref": "#/definitions/Color" },
558+ "LightWaveLength": { "type": "number", "format": "double" }
565+ lightInlinedSchemaJSON :: Value
566+ lightInlinedSchemaJSON = [aesonQQ|
571+ "NoLight": { "type": "array", "items": [] },
572+ "LightFreq": { "type": "number", "format": "double" },
576+ "enum": ["Red", "Green", "Blue"]
578+ "LightWaveLength": { "type": "number", "format": "double" }
585+ -- ========================================================================
586+ -- ResourceId (series of newtypes)
587+ -- ========================================================================
589+ newtype Id = Id String deriving (Generic)
590+ instance ToSchema Id
592+ newtype ResourceId = ResourceId Id deriving (Generic)
593+ instance ToSchema ResourceId
595+ -- ========================================================================
596+ -- ButtonImages (bounded enum key mapping)
597+ -- ========================================================================
599+ data ButtonState = Neutral | Focus | Active | Hover | Disabled
600+ deriving (Show, Bounded, Enum, Generic)
602+ instance ToJSON ButtonState
603+ instance ToSchema ButtonState
604+ instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (Text.pack . show)
606+ type ImageUrl = Text.Text
608+ newtype ButtonImages = ButtonImages { getButtonImages :: Map ButtonState ImageUrl }
611+ instance ToJSON ButtonImages where
612+ toJSON = toJSON . getButtonImages
614+ instance ToSchema ButtonImages where
615+ declareNamedSchema = genericDeclareNamedSchemaNewtype defaultSchemaOptions
616+ declareSchemaBoundedEnumKeyMapping
618+ buttonImagesSchemaJSON :: Value
619+ buttonImagesSchemaJSON = [aesonQQ|
624+ "Neutral": { "type": "string" },
625+ "Focus": { "type": "string" },
626+ "Active": { "type": "string" },
627+ "Hover": { "type": "string" },
628+ "Disabled": { "type": "string" }
633+ -- ========================================================================
634+ -- SingleMaybeField (single field data with optional field)
635+ -- ========================================================================
637+ data SingleMaybeField = SingleMaybeField { singleMaybeField :: Maybe String }
638+ deriving (Show, Generic)
640+ instance ToJSON SingleMaybeField
641+ instance ToSchema SingleMaybeField
643+ singleMaybeFieldSchemaJSON :: Value
644+ singleMaybeFieldSchemaJSON = [aesonQQ|
649+ "singleMaybeField": { "type": "string" }