Skip to content

Instantly share code, notes, and snippets.

@hoodunit
Last active November 20, 2017 15:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hoodunit/c1b1e9bd02b851135fa2668b5a6db066 to your computer and use it in GitHub Desktop.
Save hoodunit/c1b1e9bd02b851135fa2668b5a6db066 to your computer and use it in GitHub Desktop.
PureScript: representing JSON values with many nested optional fields
-- PureScript representation for the JSON object
-- accepted by an API.
newtype Job = Job
{ apiVersion :: (NullOrUndefined String)
, kind :: (NullOrUndefined String)
, metadata :: (NullOrUndefined MetaV1.ObjectMeta)
, spec :: (NullOrUndefined JobSpec)
, status :: (NullOrUndefined JobStatus) }
derive instance newtypeJob :: Newtype Job _
derive instance genericJob :: Generic Job _
instance showJob :: Show Job where show = genericShow
instance decodeJob :: Decode Job
where decode = genericDecode jsonOptions
instance encodeJob :: Encode Job
where encode = genericEncode jsonOptions
jsonOptions :: Options
jsonOptions = defaultOptions { unwrapSingleConstructors = true }
-- Type class for creating an empty value so you can only
-- specify the fields you want.
-- Making it a type class allows you to use the same name
-- for different types of objects (and makes it less likely
-- that names collide).
instance hasNewJob :: HasNew Job where
new = Job
{ apiVersion: NullOrUndefined Nothing
, kind: NullOrUndefined Nothing
, metadata: NullOrUndefined Nothing
, spec: NullOrUndefined Nothing
, status: NullOrUndefined Nothing }
class HasNew a where
new :: a
-- Helper lenses give a nicer syntax for setting and updating
-- fields, especially when the fields are deeply nested.
-- The lenses are polymorphic so you can use the same lens
-- on different types of objects as long as the objects are
-- a newtype with a field of some specific name containing a
-- newtype.
apiVersion :: forall s a r r'. Newtype s { apiVersion :: r | r' } => Newtype r a => Lens' s a
apiVersion = _Newtype <<< prop (SProxy :: SProxy "apiVersion") <<< _Newtype
kind :: forall s a r r'. Newtype s { kind :: r | r' } => Newtype r a => Lens' s a
kind = _Newtype <<< prop (SProxy :: SProxy "kind") <<< _Newtype
-- Example usage:
-- Create a Job here with all empty values, then update it
-- using lenses. The lens syntax is convenient and powerful,
-- although the weird operators will be a barrier to getting
-- started.
testJob :: Job
testJob =
(new :: Job)
# apiVersion ?~ "batch/v1"
# kind ?~ "Job"
# metadata ?~ (new
# labels ?~ (StrMap.fromFoldable
[ Tuple "service" "search-test" ])
# name ?~ "search-test"
# namespace ?~ "default")
# spec ?~ (new
# activeDeadlineSeconds ?~ 600
# completions ?~ 1
# template ?~ (new
# metadata ?~ (new
# name ?~ "search-test"
# labels ?~ StrMap.fromFoldable
[ Tuple "service" "search-test" ])
# spec ?~ (new
# containers ?~
[ new
# command ?~ ["/bin/bash", "-c", "npm test || true"]
# image ?~ "search-test:test"
# imagePullPolicy ?~ "Never"
# name ?~ "app"
# env ?~
[ new # name ?~ "ES_HOSTS" # value ?~ "http://elastic:changeme@localhost:9200"
, new # name ?~ "ES_CURRENT_INDEX" # value ?~ "testing"
, new # name ?~ "ES_WEB_INDEX_ALIAS" # value ?~ "testing_web"
, new # name ?~ "ES_WORKER_INDEX_ALIAS" # value ?~ "testing_worker"
, new # name ?~ "LOG_LEVEL" # value ?~ "error"
, new # name ?~ "NEW_RELIC_ENABLED" # value ?~ "false"
, new # name ?~ "APP_ENV" # value ?~ "testing"
, new # name ?~ "NODE_ENV" # value ?~ "production" ]
, new
# args ?~
[ "-e", "bootstrap.memory_lock=true"
, "-e", "discovery.type=single-node"
, "-e", "xpack.security.enabled=false" ]
# command ?~ ["/bin/bash", "bin/es-docker"]
# image ?~ "docker.elastic.co/elasticsearch/elasticsearch:5.4.0"
# imagePullPolicy ?~ "IfNotPresent"
# name ?~ "es"
# env ?~ [ new # name ?~ "ES_JAVA_OPTS" # value ?~ "-Xms512m -Xmx512m" ]
# ports ?~ [ new # containerPort ?~ 9200 # hostPort ?~ 9200 ]]
# restartPolicy ?~ "Never"
# terminationGracePeriodSeconds ?~ 30
# dnsPolicy ?~ "ClusterFirst"
# schedulerName ?~ "default-scheduler")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment