Skip to content

Commit f715c96

Browse files
committed
option sortRecordFields
1 parent a61aef0 commit f715c96

File tree

4 files changed

+17
-4
lines changed

4 files changed

+17
-4
lines changed

src/Data/Aeson/TH.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,14 @@ import Data.Aeson.Key (Key)
124124
import qualified Data.Aeson.Key as Key
125125
import qualified Data.Aeson.KeyMap as KM
126126
import Data.Foldable (foldr')
127-
import Data.List (genericLength, intercalate, union)
127+
import Data.List (genericLength, intercalate, sortOn, union)
128128
import Data.List.NonEmpty ((<|), NonEmpty((:|)))
129129
import Data.Map (Map)
130130
import qualified Data.Monoid as Monoid
131131
import Data.Set (Set)
132132
import Language.Haskell.TH hiding (Arity)
133133
import Language.Haskell.TH.Datatype
134+
import qualified Language.Haskell.TH.Syntax as THS
134135
import Text.Printf (printf)
135136
import qualified Data.Aeson.Encoding.Internal as E
136137
import qualified Data.List.NonEmpty as NE (length, reverse)
@@ -461,8 +462,10 @@ argsToValue letInsert target jc tvMap opts multiCons
461462

462463
argTys' <- mapM resolveTypeSynonyms argTys
463464
args <- newNameList "arg" $ length argTys'
464-
let argCons = zip3 (map varE args) argTys' fields
465-
465+
let argCons_ = zip3 (map varE args) argTys' fields
466+
argCons
467+
| sortRecordFields opts = sortOn (\(_, _, THS.Name (THS.OccName name) _) -> name) argCons_
468+
| otherwise = argCons_
466469
toPair (arg, argTy, fld) =
467470
let fieldName = fieldLabel opts fld
468471
toValue = dispatchToJSON target jc conName tvMap argTy

src/Data/Aeson/Types.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ module Data.Aeson.Types
145145
, nullaryToObject
146146
, omitNothingFields
147147
, allowOmittedFields
148+
, sortRecordFields
148149
, sumEncoding
149150
, unwrapUnaryRecords
150151
, tagSingleConstructors

src/Data/Aeson/Types/Internal.hs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ module Data.Aeson.Types.Internal
5959
, nullaryToObject
6060
, omitNothingFields
6161
, allowOmittedFields
62+
, sortRecordFields
6263
, sumEncoding
6364
, unwrapUnaryRecords
6465
, tagSingleConstructors
@@ -733,6 +734,11 @@ data Options = Options
733734
-- ^ If 'True', missing fields of a record will be filled
734735
-- with 'omittedField' values (if they are 'Just').
735736
-- If 'False', all fields will required to present in the record object.
737+
, sortRecordFields :: Bool
738+
-- ^ If 'True, fields will be sorted alphabetically in record encodings.
739+
-- This is useful for comparing JSON encodings
740+
-- or when the whole or some parts of JSON encoding needs to be signed,
741+
-- to avoid multi-stage encoding/decoding for signing and signature verification.
736742
, sumEncoding :: SumEncoding
737743
-- ^ Specifies how to encode constructors of a sum datatype.
738744
, unwrapUnaryRecords :: Bool
@@ -748,7 +754,7 @@ data Options = Options
748754
}
749755

750756
instance Show Options where
751-
show (Options f c a n o q s u t r) =
757+
show (Options f c a n o q d s u t r) =
752758
"Options {"
753759
++ intercalate ", "
754760
[ "fieldLabelModifier =~ " ++ show (f "exampleField")
@@ -757,6 +763,7 @@ instance Show Options where
757763
, "nullaryToObject = " ++ show n
758764
, "omitNothingFields = " ++ show o
759765
, "allowOmittedFields = " ++ show q
766+
, "sortRecordFields = " ++ show d
760767
, "sumEncoding = " ++ show s
761768
, "unwrapUnaryRecords = " ++ show u
762769
, "tagSingleConstructors = " ++ show t
@@ -854,6 +861,7 @@ defaultOptions = Options
854861
, nullaryToObject = False
855862
, omitNothingFields = False
856863
, allowOmittedFields = True
864+
, sortRecordFields = False
857865
, sumEncoding = defaultTaggedObject
858866
, unwrapUnaryRecords = False
859867
, tagSingleConstructors = False

tests/UnitTests.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ showOptions =
281281
++ ", nullaryToObject = False"
282282
++ ", omitNothingFields = False"
283283
++ ", allowOmittedFields = True"
284+
++ ", sortRecordFields = False"
284285
++ ", sumEncoding = TaggedObject {tagFieldName = \"tag\", contentsFieldName = \"contents\"}"
285286
++ ", unwrapUnaryRecords = False"
286287
++ ", tagSingleConstructors = False"

0 commit comments

Comments
 (0)