Add notSerializeDefault default field option
authorOleg Ponomarev <oponomarev@google.com>
Mon, 12 Oct 2015 14:25:32 +0000 (16:25 +0200)
committerOleg Ponomarev <oponomarev@google.com>
Tue, 13 Oct 2015 14:21:23 +0000 (16:21 +0200)
Default field with notSerializedDefault flag set is a default field which
will be serialized only if it's value differs from the default one. This
flag can be set by using notSerializedDefaultField field type instead of
defaultField field type.

This field is introduced in order to fix a bug of inconsistency between
haskell and python config modules which leads to inconsistent config
after ganeti updgrade.

Signed-off-by: Oleg Ponomarev <oponomarev@google.com>
Signed-off-by: Klaus Aehlig <aehlig@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>

Cherry-picked from: c0a2c62b9ad96c3e35cae0ffdcdf63a09164f537

Signed-off-by: Oleg Ponomarev <oponomarev@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>

src/Ganeti/THH.hs

index 5a9926c..77ed0cc 100644 (file)
@@ -61,6 +61,7 @@ module Ganeti.THH ( declareSADT
                   , andRestArguments
                   , withDoc
                   , defaultField
+                  , notSerializeDefaultField
                   , optionalField
                   , optionalNullSerField
                   , renameField
@@ -176,6 +177,9 @@ data Field = Field { fieldName        :: String
                      -- ^ a list of extra keys added by 'fieldShow'
                    , fieldDefault     :: Maybe (Q Exp)
                      -- ^ an optional default value of type @t@
+                   , fieldSerializeDefault :: Bool
+                     -- ^ whether not presented default value will be
+                     -- serialized
                    , fieldConstr      :: Maybe String
                    , fieldIsOptional  :: OptionalType
                      -- ^ determines if a field is optional, and if yes,
@@ -192,6 +196,7 @@ simpleField fname ftype =
         , fieldShow        = Nothing
         , fieldExtraKeys   = []
         , fieldDefault     = Nothing
+        , fieldSerializeDefault = True
         , fieldConstr      = Nothing
         , fieldIsOptional  = NotOptional
         , fieldDoc         = ""
@@ -206,6 +211,7 @@ andRestArguments fname =
         , fieldShow        = Nothing
         , fieldExtraKeys   = []
         , fieldDefault     = Nothing
+        , fieldSerializeDefault = True
         , fieldConstr      = Nothing
         , fieldIsOptional  = AndRestArguments
         , fieldDoc         = ""
@@ -224,6 +230,13 @@ renameField constrName field = field { fieldConstr = Just constrName }
 defaultField :: Q Exp -> Field -> Field
 defaultField defval field = field { fieldDefault = Just defval }
 
+-- | A defaultField which will be serialized only if it's value differs from
+-- a default value.
+notSerializeDefaultField :: Q Exp -> Field -> Field
+notSerializeDefaultField defval field =
+  field { fieldDefault = Just defval
+        , fieldSerializeDefault = False }
+
 -- | Marks a field optional (turning its base type into a Maybe).
 optionalField :: Field -> Field
 optionalField field = field { fieldIsOptional = OptionalOmitNull }
@@ -1057,7 +1070,14 @@ saveObjectField fvar field = do
                                    Nothing -> [( $nameE, JSON.JSNull )]
                                    Just v  -> $(formatCode [| v |])
                               |]
-    NotOptional ->            formatCode fvarE
+    NotOptional -> case (fieldDefault field, fieldSerializeDefault field) of
+                     (Just v, False) -> [| if $v /= $fvarE
+                                             then $(formatCode fvarE)
+                                             else [] |]
+                     -- If a default value exists and we shouldn't serialize
+                     -- default fields - serialize only if the value differs
+                     -- from the default one.
+                     _ -> formatCode fvarE
     AndRestArguments -> [| M.toList $(varE fvar) |]
   where nameE = stringE (fieldName field)
         fvarE = varE fvar